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 16020b31ae640eddda12cae66d54f48a7c4cb65b..5d41ebadf15e9250adb9a6d5258e21281b23870d 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 156319fc5b80a9db21ccb5ff211d623c7b1f7a97..3544968f43cc05f0edafbd93187df3999af6e424 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 2f5b80be07a30bf70f3d3fd7555a52009edab804..f0ac14b70ecbf4107afe8dd36aa60fed2d2dfc90 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 73a5a66ddca655ce547e9f1bf9e343bebbedf065..9d8d9d2def5b35dd367392210d0979190e5f86c8 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 0a54ed0d63c99377becfbefe2273a46dd1087f75..274df44d8b1b50ae7fea4c0b81e0eeac61d8826e 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 5fca9f5e10a3aa8bc1b84069904fd99c00f6db58..d45209abdb1bd979f63f0b0b3c888038fbba2779 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 77f47ff5ee02b9beb661f5e61f1b967105a2ab01..5bb793ec926c1f6ed84acb7abc2a48e36a440c3b 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 feb2e4a870755ababf8d132b8d5c87f95a41ea9c..4a251b7f11e4edd1684271e4ff1e156d540e94eb 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 6aef7dbbde44cf516cc7450141d01bd97aa9267f..680451695422a2a312a7d46349d9b0ff27b3931f 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 0e95c2ca105ca891ebbeab8983b3f0f5461ddaea..6158f831c761f7242b0c0afffcea21b1c570205e 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 0a1ca1487fa97c72fe0f2101eeefb747e9df57ef..a133fd8d081ac23f74f881ef387f71c9de6fc585 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 9a17ab5036a4cbb4dba37e420ecc5d5bed071d0d..c59d953463417bb1a6705416deadb5cd19a21ab3 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 4b0318c99507f437455d047163618bd6e0a0f9d6..3c9a8c4a25eb89a87448f18fd7b550b4c5e74c55 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 53d99edd1d75acf45fc63152b111d5fbcc6ea202..92a94e1068c2b34226160d32e249d2db7140cefa 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 70d00dfa443d2f2f85d24f662c17606b034673c3..9ade80f81f96c4abaacd17723146bbe362e41ea6 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 77cf7ac949af76a818f7e3836ff141041aa941d7..c0e0a9ae7b3d9bfb4a344d00490759d2475e013d 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 bbbabffc682a93feef010381dab1edf94b8c0394..7970e3713e705ce91c3f0dbceb51efc6c876d2a6 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 ee39acacf6f8512cb81eedaf0d06685bbf004144..01196e19afca3b0050f9c056b1db2841e89d0334 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 620ebb3b9baa39b1c2e5472a613324ae13d68f13..e4c89b261546c367463561adf0017ca7ea18a565 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 e4fae6026e793a080fe4d1814bad04b110bfc70a..6adab27f646e668eeb46d92ee5fe6ed560ad15c2 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 db3b3ff70d848c555575f34849031035a0314c51..f333a0ccc29b3ad31fe5db6a18b448ef1ffaeeef 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 85f4875d16ac0d63d246d364b2e60f07d3c32b39..a0578751c1e38c475c18dfd183b66e2c7844e0ad 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 8cde64a71edba2c15dd24026c705b15b6016e162..fbd8078fd7ada51c7e1cff8e08825b10cef66647 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 78b2bcf316a3ed7a2205529d339b8eeabf2ac998..f433fc6db3c69f790107846bf79b924ede4f8165 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 48942cacb0bf490ef7da785536702bff0d7b2a90..a59533410871be40877625debd238594bdf143ff 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 3ca3971109bf627fc299fa971c624c953619841e..8f7982c70d72cc797a18c15720056bb96f573ebc 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 9921ef285899f03ccca71c13ebbac0a7522a359e..1a56fc50768971c1c34d3ecb77e3d31a3c79ae24 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 ba5d77008a85514635f717993deec212d95276b6..88cab66fd77fb566e26e28008c250a8578202cc5 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 2aa5503ee200763bf5e841fbdcd77f0422247d1d..afc48fc163b5903bdf6d41018b8dfb961a4a1b85 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 91822ce258317df500271f8d28cf540e30cb19da..dca326e0ee3e1e76cf9c25da30ea7a85acbf2752 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 50a3033b5e150c0c1a9456ee540b4d411b016085..bcff34665192460fd6c8bcb6e133627fbd7c9be4 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 7bd81168e063375b8f55545fb53b4d0341cb4383..1f1087a5f0757b8c0db10ee429e098238a23d408 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 32070762d24c44f0efc47a7bb1e99e2cf9d18291..716ad9b23c9aa73115c21ee86538cf99cd7ec173 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 a5c845338d6d70f5c0eec37b8572cd11bd0d0a9c..a9548de56ac997c1e41f0a484b9da60fa24bab5c 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 1649117e6087d3eb7462c4a73452654d32a29e00..e56e00655153a7ac3ebef87c3d4cd85f0aa56961 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 f1c433daef6be56f395d85c691e96048357c1ad2..099c5a4be95b47d737b91a18d266a01df3614987 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 3d041d0d16e81f2632abec9bb72a4360e632e74a..d3f3a60fbf252fc0db3d7498320d80fb0d3beaf3 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 c792774be59e625a204065ad761538ef326fa4e5..3e57d09246e668c14fb44c6b949494df273b29ae 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 824f24ccf401f010c1d77bdc354bbf02a999f1e1..08af5caf036db8997cac6d58e0de5022515d2473 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 e6f51260ff3285cc412d63168e28cd70cd68207b..3621cd5e1eef41f4ea8e3404b29f65ae89006da5 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 4c53304e72f1b042fdab9b034771017a45f527d0..ccdd8b587a74f6869e3e7d321c7b19b30a2a7476 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 8a2774b5834b5bd07d30ac3c544d5672b57ec835..6b0dfd5c17baccb3232f032738a7a5c53efd28c9 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 abff8d834a6a27de12a6217d80afa842cdd64f60..6758ece324b1c259209b8c30c9cca885f4c73692 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 298291211ea4dd8f647d47cc80f077d19fe82249..f1de3247c1b74bdbf22a84bc2bdfe0643de4621d 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 8a88ddebc1a21bdb6a5d424dd2065c1a4e190f12..fcc3bacfd8bc27dec3ace9d67924dce2641e72d9 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 591bbd012d63c184fccaabb8ed5f730281cb1407..aa40b074b8648345ba944f3426b41c787d477e13 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 5d7dbabbb78449ae22f8a2a12174a00e6e292f12..f378922906f6a2e1c7006545973746df80c6f173 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 45730ba60af5411f1f0c13a8d3078d37a9b94c25..326f29b270ad140dfa421203f719d6d4c9b3da1e 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 f6316ab66385e740095daf6c52aee90fae36ea28..54ef6b6b9189bf26524ad7f093c5466b5fe7e118 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 a3448bfa1c827971f6d0e9c33e31c7636a0ce1b9..98a28130e100fe8244cfaf427266493863252e46 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 b052d76cf8b63e70ad8d3f1dca79cbed6698f87d..678776b6012a2b3effde9aa4b952fae5ea6b2027 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 0df9befdaecca610aafeac98cdae4daf6bb9453a..78c06e05c8e5e146db91672554cf4c9c9707b251 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 8346bcb04ad79efb85230021f1cd66fc3803010a..93a0bd2efc058281e65b29ceb37170a1fa1e0718 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 797607460735a295994527aa536822e69ca35e3f..9963247706f21329424a752c1f69bdd078462ee7 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 3538a214fff156d461322f7e10b92821f9331484..352f5e9c759bc3f5da8d7b4a1d6f7c754a794da5 100644 (file)
@@ -36,4 +36,4 @@ Example:
             kcs_chan = <2>;
             status = "disabled";
         };
-    };
\ No newline at end of file
+    };
index 4d61fe0a98a4de48feb35fcfe56cef12b2fcb2dd..dc129d9a329e7e6168e28179dd57630f858c38e5 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 f936b5589b1953030adc2563c88555398a49e839..59b8dcc118ee331206f30a02c9cea49e15c796b7 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 13e70409e8ac6250676eba2d6e31be6187410168..ccc5358db1316508abae3c2f50f90acb6fc07047 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 c269dbe384feab159be98e713a328585499e473a..bf9d7d3febf102e8265b3cc1010b7da92e0320ed 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 15dbbbace27eb35be924af9c1657bbd374ffaf79..50e87df479718f0a2f4fac762301ff4cd7c3eb91 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 45c9978aad7b091229865577d1a3efd2a98288ce..eb7eb1b529f070be3236f3cdedb61a494fe46fb0 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 fbd4da3684fc7939d1ff92cdeaad16cc70048c2e..e5a411518be1ed2c902f34a1d9a623fd6e4ace54 100644 (file)
@@ -57,7 +57,6 @@ patternProperties:
   "^nand@[a-f0-9]+$":
     properties:
       reg:
-        maxItems: 1
         minimum: 0
         maximum: 7
 
index 0b7c3738b66c39406aa0bff9925456309c13b6ce..82156dc8f304cb8b660db8ef1b035add725c24b8 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 4345c3a6f5300725d72b5dd3c93f6e9a7c82ddb2..945be7d5b23608906807da1b314efc0b86382207 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 5475682bf06e1a76f61bc063a9063e5eeebf08aa..5df413d01be277262e452e0a10da0ecdcbdb7b16 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 ec5d889fe3d83d17bcec0171893fed7519a28cf4..5df413d01be277262e452e0a10da0ecdcbdb7b16 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 e3e1603f256c1a55ce956a403fce855e7bf58e0e..cf8a0105488e64c56ab223aa70c61f374fa33f1d 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 9b9e5b1765ddf65c1f717ec756db1719af243079..2399ee60caed28fe05a0f770f5d5eaa7cb541307 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 cb694062afff0896ed6e67c2ee12c7a9826f91a9..7d48782767cb555c32d51d1722f067c9964990fb 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 68f7d6fdd140e2aa86ed8f82ac27ac38249c8931..96ffd06d2ca8707b2d3a0b831b600c977633daca 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 b9165b72473c10f6245bd656a6ac169d67cd3257..3abeecf4983fac0907717a472a9f19e7c9b74669 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 6ac98b3b5f57b5a9e8dff47c0d51ce1dd7562ab9..c9f5c0caf8a9ccbad2b15fabae86c24166824dd8 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 daedb15f322eb05d70c12cf3401b8209236531a6..9fb682e47c29b9e6c41cc06c8ea3c14ee92cbc02 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 d46188f450bfb7cd33f8f538b337830f16505cd1..503a8cfb31843e5532d3a611b82745f84c926418 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 cf96b7c20e4dbba2b083fd0af7a23ed91d32943e..328585c6da589cf16700e62e7fd2534d1ec06252 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 ed34bb1ee81ca7105876d7e514c6bc81ec070812..4980776122ccc0f3d8864f4ba646c519011305a7 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 3fac0a061bcc7c5b1cc6dbfa76b4b006e6876f48..ac6d614d74e05baba0c179a3709ca278974f2322 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 524a16fca6665a9335f0574ebe2a722f38101273..e4e01c05cf83c5627b9c9026e5e24ed63c18dcce 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 6c0ea155b708980c7a6cdaeeccc962bd383f66cf..2932f171ee857a822220f7eef1a587687f878aad 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 a47dd990a8d3ac5630ac47efbdb99c17ba1d4d13..10dc4f7176ca127a788f693763ffc9b1e85c1b5b 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 29b72e303ebf938fd40aabde70f02b941767b15d..51efd2085113eb53cb934ef6c0d2854a1922749e 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 83f4bbac94bb19dbd965115a6075855c60b63ab8..a1264cc8660dcd59070395ceaf93b83058886c0e 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 cef2b5855d60fdaef2c62960e19dd0f087564cc5..fcd37e93ed4da92df7787982e3ba60e1ce1e85bd 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 68e93d5b7ede1cd8874e8c24b29289b4f8deb7bd..c9782397ff14831c957e0c60da6cd0e707d876aa 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 6dd72f8599e91dd89913098ea8ee94808389025a..7b151894f5a0df4158e1f5186bb9a2c469448fed 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 86ecdcfc4fb8a1fe70617186de1208ccb7bf9a2a..d4697396887387eefd1246e972a1c6c1e4b06374 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 195a7a0ef0ccbc842f5a65c4e1d7c57378ee6abf..3354a63296d99a85844b6031b2e2a8f41efb5824 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 5034eb6653c74a4294e57f60b1b83291a82ad077..a7dd213c77c6f14eade7aa56120e9b2aa05a305e 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 f15443f6e78eb77b5edab227069a4f953839b28c..da52df6273bc43bc1587bf333278efb7f1d2e250 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 fa97f609fe45146c665e0e6a535bc1602ff6bf70..a56cb882830cc1fc24978928ea801ad551d7c71d 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 e70c79bbbc5b28617ecf91b30151933685480fdf..cdec1eeb2799439386cbf62f48ffe4be6643b047 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 2b8f77762edcec12da0447ae108d17b8a7f809b9..a50e7468419563caf2147183a6c121056b8a61c1 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 769ca83bb40dbf7e3e20bac9351d1261df1066a6..be034d329e10f99bfc5f85b3b5a5b760f55e327e 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 665aadb5ea289fc7bca563d35e21557ce7fa9124..7462e3743c68e3f9834cc55a5d2d16db1b1b3bb3 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 bfd33734facaba73c963e3e26351651b4f38fc5d..e9b8360b32880f127d1e1c6b7bc933ec7ccc920e 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 10a6dadc008eb38d6cae1f439b364f52efa82194..6a7c8a92fdb0bf1c54811670d8730500a123f163 100644 (file)
@@ -121,4 +121,4 @@ Example
                                regulator-max-microvolt = <5000000>;
                        };
                };
-       };
\ No newline at end of file
+       };
index 3cba12f855b783b6d672e5935362b5a54080bcad..20d351f268ef3bc5a2ae690310545efe3fa93dfd 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 c6b5262eb352e9569b0be3353a9ec81bae5f2ae5..6fdffb735fb98e77ece85951d0c4e5e0307f4dbb 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 9d3efed55deb243ff26e440f87496cfb23683c26..a6b19485c9dc09ba2c88091164e96ca33f2f59a7 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 80ae910dbf6c388021ff5cb590e00f9f035cefd1..47b868b5ab0114707acba55ab24b6fd0a525589e 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 49eac0dc86b0954f22903ce24657857fd68ce6c3..aafff3a6904d063cb8bcf7297f5fba29c7817d9a 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 8e5265e9f6585c3d5cc9f2605246329f60d85c14..66780a47ad8595576458f0b639d6b892c57f633e 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 d3b4f64159202a7f2424e9c4945c8a65b90ceefb..059f6ef1ad4a5a587055615355cbae5c3140f26c 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 1acf806b62bf96221818fe9aa016e4601efd1387..18b79c4cf7d561f78cc64783417ab0a1553f0375 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 4af9aae724f0bb6c3d481cfc4cad8ccbce8e23e0..349f2dc33029d6b64ac148f139bb16df590c954b 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 d26308af60360b30f086a684affd0945e65a26f0..6cd750a03ea0fb9e3e2d45cae167b02e22776d85 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 253f73555255091b5abceafce9c103ca6a3cd771..3a7ffb3d87f39a3c752deec6e029c9626116141e 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 2806e5544e43531e0892ea71f58ffc1b9c0ddfe6..f388545a85a7539358df86cf90d6ca5628539066 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 4a0a9c3f4af60cc701a40e6bc60ee6751b933961..9e27c843d00ea0602e391f760c05764066a544c0 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 f7b5e4ff0de3e1a196cf7d66f4780345e24829b1..496fa28b24925ceee45f272566e7eb82dd4c7ec9 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 a226061fa1098bebeafc6da0095c2da7d56e42f4..d750b6926899c039cabc0fa8408a8a89047e6f22 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 68604e67a495fce4db18e0c76e58237c73080854..8db0121d0980c4b7293f76eb8331d09162cc21e9 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 f9796b9d9db638363955925621ccc39649dd6716..d5b05d3e54baeb95aaed199fc8e966b115af01c3 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 781042b4579d92b83f9c1207ab053d6cf6465e67..216dc0e1e6f2efca39167785e7d32e2078f0b183 100644 (file)
@@ -101,6 +101,7 @@ needed).
    filesystems/index
    vm/index
    bpf/index
+   usb/index
    misc-devices/index
 
 Architecture-specific documentation
index 47f86a4bf16cadbf258ccc8078780486c86f4370..0eb61e67a7b784b0ccb31f17f464363dbaed4f82 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 1ab7294e41ac416194079fd9f93d9c52d3fd9810..f6c6b74a609c678ccde1e73cf15d17466497c089 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 e774e760522dc4de1d3f2e900bfd92cf557938c1..b25548963d70194accda66b84aa89866e2c06d2e 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 9274cdcc9bd23bc23f8c942cb8479560819d8292..093f2d79ab95d9853b8d088f8d47f5acc650ed56 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 dfd1f45a3127f8fc0ef2c039f7de46b9dfac030b..a57f92dfe49ab60a082efb072042d14f23a52897 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 1769f71c4c203907abf2da3b94c5d322be269ab9..81842ec3e11617eded3fb009e40426bfda28a285 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 3bfbf66e5a5e008edd60473f5345e76eecf72425..4e373d128d9812ddcbeca4b86d346e708bc4f49f 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 383b292966fa1472492533e974da8cc0a0198633..2cd6250b289676ac0091f6a6299d33fabcd4d2f7 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 aafdab887b047b6f14c85f29660d838b2d3f4143..559586fc9d379921c98a87841792055c15573082 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 da24c138c8d131bea63aeb652af3d6fc373514ef..da210651f71486dde5e27bcbee3ab62aefa25080 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 1bb8bcaf8497703f7cdd61538ca1374f0e8ac622..635cd6eaf71495e081de44774e489d622323fcf4 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 f3f0d57ced8e1827fe8e8e6dc49808b18c9253fb..df1f4338b3caf3e466e783fec42b767cef1ad72c 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 618e4979960bca2e4e9a4886279cd3fe780a2182..211ea3a199bd6eda3fccd794d86d140c6ee1ecf3 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 3e4868a6498b2224f5a174f7da5abf287dc6580a..2c5d00ba537e3f761a02b7f7f83a8d30180a2193 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 c47b328eada033257e30c89a0f1678d030b5b95f..e8d19c3cb91f226adf2a6444e61eca4c75b406c7 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 b3314e0dcb6fb0d3f92509365677a6735fa2f9c8..12dee59b011c0a1ebc10e1102a0ef6efa13b252a 100644 (file)
@@ -8,8 +8,6 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-KBUILD_DEFCONFIG := defconfig
-
 NM := $(NM) -B
 
 LDFLAGS_vmlinux        := -static -N #-relax
index 02f9f91bb4f06967cca66f736efb5c1ef21bbbf9..71ded3b7d82decb113a0dd25c7e89801fa2b2b57 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 1c8137e7247b40526de5d703977e3cf7cbcbf148..8383155c8c824f486c2cadd7e46178ca627bfe5a 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 03a0b19c92cd049d1aba5235d3fb9c8734a5b904..ee6d1184c2b1b557fef8bef69a1ae9cf2c90daa3 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 5b5119d2b5d5e51709b5f3450c90a943f9d63b63..dc739bd093e31956782f8b808e60f1f64102b0cb 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 0bf1468c35a38daa707546e40cfde9a6a376ae48..62c210e7ee4cdc5046b422d819a997e03134652f 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 d850feb5cc0a5c0dfd5e6c4e84136d9fdbbe4ae5..2bf1ce39a96da6e5ef55cb65f01c5c02a7521907 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 1252522392c73f475150061672cff5251773a4e5..1d8bfed7830cabd9a58dfdbe16c92d96713edb45 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 03ba90ffc0f8f1130dd56fef97ecb9bf7a058a44..7e0486ad1318cdf3037b0689340f4faa407ed13b 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 6b7644a383f60d3a8a5aa6cdc7d6201bbc6ac075..40002416efec221345c6c693381a7d2b3956bb5c 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 f80418ddeb608b2de4c723296d36d336bb11755e..8a37c8e89777fcb48944e7ec2dc7dd842cd7502e 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 71ac1c8d101c68b0a3275e4bcf2e083443959797..40e9034db6013bc9afe6013a9ed3e22891d39fad 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 c038cff6fdd34fe1b7821583e1fd71a444330a14..a2a68b75197186ec219ce6d74c724c6712d7704c 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 3ebf9718288d9946ebf502fe88010c9339ee88d9..0c2d3d0d4cc69594226a97df936cdde1fbc10cd7 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 4602464ebdfbfccd9296593ed5dd8b15f55305ff..a4217c1a5d01178c53346ea3f48ed3415aa956fd 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 ed005870671ae2646320f8c3cd548d4f13c3d50d..e57dbcc89123e1ae515fe10557fc13d3f941338e 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 406fd2a9a88f4012ca3fbbd39ec0d52d3af79ff2..bd5be82101f321b2879c91b15e3628cf5d29ee7c 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 998075d3ef8666e55e3915ef140f82969b2dbff4..d068958d6f8a44e45ff24d1049e98de43823efeb 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 fe6ec9b580b9c032c55daf2e0ed5544e3c3b1672..fceb1e525d26b9541859c906b79e369c95681186 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 1aea01ba12628463a0942a26d9cc740d9f0db081..52b82559d99b3d608b4347a4060b7e686311d72a 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 439bb6a59a04a2d8008487bd6946614304a6b378..4789c60a86e34552411367282be7309f0d8f779a 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 006d27ee4fc6435273062fefa72e3779a2656746..7d6291f23251e74644bf0694ae97ab38c7a4bd2b 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 1aa2586fa597b8d51bdb8ae1af6b493050b20eb1..d9a0038774a6d9004e9d07bc050999e8a825f03a 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 0f5faf30d9bf67943c240ea277242e4b13289e30..d546efad7e975f3dbc871be80b3870382cf01e41 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 be8d87be4b9384eb3be44ea171c26a1fc16e2b87..598b636615a29ac5aba506242aa1119418b4d52d 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 c085aec9459bbaf1f5e1cbe93933c36d6269c664..a36ff61321ce39ff10e136425e12a125deb8e085 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 e3d3fd0a42683b32c9d5296a09e4391189ff649e..bb1f1dbb34e8f9f544cff4f6f22728eec660be54 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 570d195a184d60dd4d8b7e2ff56c8b6a8e67fe82..e3a15c751b1398e911c19c3a879e9d1e766410f4 100644 (file)
  * RAS Error Synchronization barrier
  */
        .macro  esb
+#ifdef CONFIG_ARM64_RAS_EXTN
        hint    #16
+#else
+       nop
+#endif
        .endm
 
 /*
index 3d8db50d9ae2f8ccff4db5722593e2f0a4a1d21d..407e2bf23676c970fbf37d4e264b39cb8f58cad5 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 2ca437ef59faf5465bc95ff8e5a779477c3b8db3..44a243754c1b88a6afb6fb3906d5d91437def643 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 034dadec7168dbf062fe19e4240e2b0f6e259a0d..d69c1efc63e71615e8de039ebc209a3e45fcbaa7 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 9f19c354b165c30b1a7c04811232b3e0ec319896..f656169db8c33bb3fa1ecac3f7fac872922c98b7 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 286f7e7e1be4b5c7e7d22f8226d4695405bc96ce..86825aa2085221eb68069d7a763456c9ad5312e6 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 cdced518378d20b9c33941230b24b896dd41c33c..14d0bc44d451b090b582e72415dcc00b313b4797 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 81693244f58d6abbe186dfac94689a8a19544887..b1dd039023efb23238e62e555caa5541d042a2ae 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 d0bd4ffcf2c463afde0c5459c8ad03d0c679d267..a7522fca11059fcea49046632e038581be820a5f 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 d819a3e8b552b47bd3019eeef6c39ccc4500a6c9..9a507716ae2fe723624d7c7de3c1b88501d5f9a3 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 ca11ff7bf55ee796f0cf82ebd2472e4ae21a3e79..1e43ba5c79b7e4faf475909c9a86c2ad98909229 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 3c33d0dd8e0e908a9653bef9790f569b2fba3945..d0cf596db82c6449aaec0f8c0492e69891b405ab 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 7e541f947b4cead10c49fbb4ffd6f09acfd1cb89..9c4bad7d71317ef927e6766a0eefaf4352e7840f 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 9286ee6749e8ce42fd498c1c1714fc216e4f67b3..ea90d3bd92539eb7585f768d3b87e565f33af786 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 678af745d881f159b451622cd2783ec86a581b32..8c03456dade6a477f62a2d051b267ae925704132 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 bd34016354ba453784fb60948ecfdaaf0f646743..e5cc8d66bf537e3c7719d96e7e75853b0f578e61 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 b8e045615961d5978c2893f5c2d4b2186fcd37c8..ffa68d5713f1d8d915612e098d8e7be672754457 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 58f281b6ca4a97d50167899cd6d5ddfb29f708f3..adaf266d8de88f818954a1414c7f7ca729fb1a32 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 c283f7cbc7024a1a4d934971fe466dda52914ec5..7ddbc849b58001fe8ed40ff0cd23d2a20c8664fe 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 32078b767f63f2b224fa30a8648a036b0b39dca1..d49a14497715f1ea09b38b681338ee9be911bb32 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 ba2aaeb84c6c7f0ed6c067373573e6cdc2efac13..29ee1feba4eb7de12d55d8c8a99f64e2577e73e5 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 d66613e6ad08035df7c817c4b5a46e4a14aa6f9a..0d60e4f0af6659df6ddf4dd7bafe0dc34749c798 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 ce933f2960496b017c4e1d550eb6aeab8003565b..f26e181d881c36f3bd15618a3e0813f56b84c446 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 2947ab1b0fa5b768a519b48fa98cba75e96ce708..acd8084f1f2c1055adc0335d87644542018aa5da 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 3645f29bd814705cf2356de7186c64f3dd16f570..1b49c08dfa2b5582a920cf20daa20dd61b3d9a9c 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 fcdcf6cd7677e0c0d02067d567f6df5255b17fe2..03c53f16ee7767bf1028bad813209ee992774f42 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 9a0c7d5090d6fb007117c217c599dc1a59bf8fce..7548f9ca1f11142c6879281521f9a751b710c87e 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 f9aab9157c4a6f0832081ba99ffa3462b4a910fb..fb1bbbd91954cdac76b8d42c4bca78acc4a7b947 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 d213bb47b717eaa5d5d4f2ef49ed652e6445f4cc..98c5716708d6103a29316faef9ed9e5a3de81524 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 7aeb48a185763f7b944388634e2dcab38a1b7413..1a338e54133420905a23fb4c68d8a7bcf323053e 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 1456c5eecbd94054690299baca2d6428f268d0e2..1a8ddbd0d23c6a2d07c9d1f42bee1f146de3fb06 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 11be08f4f750aa93068d922d1b7f496800dc6655..205ac75da13d6b095ebc904a2c8c11b921969775 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 70d3200476bfebee57f493e2eb70d29696600166..d50fafd7bf3aed0fac0729312b2d3aecd905e0c4 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 a25643d258cb55be5830d262590f014f1d064d07..0ba4ce6e2bf3ae3b5bfa7d366ebd4f6723baf138 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 27808d9461f477a26d6007ba2ba72f7b2db047f1..aa16b85ddffcc8a4ce5dcac613387ba9f0d8c767 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 4ccb465ef3f2e2588ce629b65260e3725eace248..7d27194e3b4511473b475d5c84344f141300a598 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 b6578611dddbfc37e9a7bea36886affe93d87411..1e76774b36ddf28c4ce72ca0a9ed4c8655ded6c9 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 bedb5047aff3de0c725b0f2029ed2e177277d727..1804dc9d8136fb72b50fdc88e22f11be96b191f0 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 0369f26ab96d6aeb934d7f6e084e9789419fd03e..2cfe839f0b3a776898595c480d66807d161910f4 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 f34d7ff5eb609e247725f942664bb80776f83752..1e8d335025d7edeeb3986f85d8cad15cf6710fa2 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 3da216988672492a17cb1eec9910874d58476713..33b409391ddb6ba394da60a84c75f8a5d5091ad8 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 f9549d2fbea3169e216381397df3e203b5aca325..ed56c6fa7be29e73348fef1da07fb0fb82470fbc 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 fd0d0639454f03c575275a83c613c630153762ba..fbd68329737f4cdf476f126ed3d7e0b7534d7c30 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 14dab5ad88ef636ac260340c625b38bc12902ae8..ccdca714202019884ccbf794923291dce728bc46 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 65ce9259081bdda89b2a783140bd4f7a8d24dd02..40313a63507570b6088ebce45719b04134186fd7 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 3cbc749c79aa26ead2a2b2dc78b9422f69a0df38..e78b43d8389f0326c476328b7dcc8ca70ee32e8d 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 d0dbd4fe96454557ffd3b187780c079dc41f97de..490e3720d69442c7cdc0fe9a0706b5d23ab64e67 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 26a9c760a98bbcc36d43f6599326addcfeace594..44b5da37e8bdc1b4fb123a0344f254b0c6ccf65a 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 f1da8a7b17ff49b4965f4f5d9e647b9e1d1e258d..a8bc06e96ef58d6e84ac37b1cc28f2fdf9ef8a6d 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 7977ab7e2ca67a0318bf7650d5c4aaa1855aa4a1..1137ef2ed3b0dbc219f85606b935988fba955a52 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 ceb97cd85ac1c06daffd14c35e7a44aa9f10e84f..a0f160ba7598744cb6643298adb7330170ea2724 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 f1fbdc47bdafd64d2e5f30923790729c6bd0afc0..79fcac61f6efb559c552e85291876891b6da575a 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 3a149ead1207167d419f69ad1ac26746e2d2bff2..4bc8cf72067e98980ce0e2189ce22eae50098c4c 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 4af9e5b5ba1c72c553fc4354b2342cbecc8f15f0..9cb238664584c6cef9b96809db406fed93beb2ec 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 43e340c4cd9c9b06e89ed82582881ea42e42afde..b41a79fcdbd93d749ebc9b4fef29078266c36dee 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 58d46665cad97b0dd1ebe30d635d5a888b4afbcc..8acb8fa1f8d69fefa3d0d47f2e72797aa392cb78 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 a8859496b0b95e902937ccde774579a1a6b60120..3335734bfaddb7bc791ea35722994ee094527e4a 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 0cae9664bf67fc32f7aa7266f695c077656653fe..07fde5bd697446db4f24c13d4e93a0defea92463 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 6c29b841735cb4be22e9e62520e77314c46267f2..64d45a8b6ca09298c2accc285e938e74986ab179 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 6a91cc2623e85d385edad2c11eb9080a56294549..5b877ca34ebf4ba715072566bfb4f6e474ff66c9 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 ea75cc966dae4fb590af2dad68e77a4894b058da..4f2059a50faee17e7da547a369d9e49ef4fd1db2 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 239162355b58c7d93a6d64951b470b2ee3a91e14..ca35d9a76e5062ea12e150310fdf3bda035e0893 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 3b795a0cab6259d66da63f676239807a4373173c..24a41f919309ecb54fbeb951815e667560658072 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 aa51b9b66fa2ef3f13104f50b0243e04b5f81556..1c074fb95df2307ffc97a9869227b66eabf64b50 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 3f53be60fb014928440ba5e3f5e7e9a985b9499e..64145751b2fd5a545f33b3fa5eab7a3ec694e3d0 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 faa5a338ac5a9c0d6919cdfe7a35331e4c8990de..feee1b21bbd5f1292f1bfa92ed89d4cbd10fdd64 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 e8276161872e58b5d20c90c1819de9e2d67c74ca..381bf8dea19369faf4cc705217c2243220d1c267 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 6d704ad2472b4e9eca7c5b6e65109bbede70a8a0..0dba7eb24f92072616460ae7cee6f90205025917 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 bb98356813154a6deccada9d1b29a03e89d686d5..ce8a77fae6a74d35f4c63780e6a55e58480020be 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 b5d92dc32844bbde507d6a8d4a89915c205aad85..51716c11d0fb35c4edf3729ce96cb7f029578aa3 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 84e8ec4011ba72a39ffa0b4b209c1f1b496dd4cf..b91eb0929ed144cceb6258c278f4bc633f9319a1 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 6b0741c9f348729fd6899a721b67aaaa222be15e..f8b3b07e42474ea02ff44a5471fa6073838a9a35 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 eb8b0195f27f2f9cec045faea0c1666b241ab7d5..56a67d66f72fbbead3aa7283ebb806c5ac7bc48f 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 fdb4246265a5a43f84e8ce54adfc6acebaaf946d..5d8570ed6cabdfa18c4058355306bf292f871672 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 e48013cf50a2b1b7cb591a110ec0125587b4eac3..e0bab7ed4123a84c655b33b9c3487e6f975fb64f 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 a6dc01a22048d7a0ab25d3af55d99900cd7e0020..e26d4413d34c139d603ecc180da09c6583f2d0c7 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 4a928e2c667b0d00e3fa07f55f7cc8f4c8c14555..abe60268335d2027df8a36b0517755d25e1789fa 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 ff81ed19c50656e5ccbf9042704b9980d0911925..61cf9531f68f26d83112ec86afc3872c0d539418 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 9f0195d5fa167f5d7817f2a231c6e9f8f31f9b9f..9b274fcaacb680b1d2cc63c2ac7c3fe57ec1cde1 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 f577c5f6031adbfb318547575ca82e87848d50e6..c563f8368b19b1bd67ec8f5d87dd08a92cf42590 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 832be5c2584f7018e814c8e5b4c691062c9b5e46..9ec86fae998050881dfcf56b760be156b5ca6384 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 629f173f60cd9dd72b2f8955a2007e2f54eb528a..6312fed48530b830e850c59627a643895592a90c 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 d836af3ccc38208b99428430ec629186281be48d..2c0a515428d61879082bcdcc42fe4558ef8dc664 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 34cc96449b304c1eb98b01bd4a30ef005118cd53..8b33e03e47b839c0e7bbe03e9e05446235d23f2f 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 3ce8a0808059b634c2b326a82d2e0c9237dd7173..8fc9daae47a2ee89a25161ff9775673ee9f37dd8 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 1c4113f0f2a87255a83fee1f0789acc4a600418e..3f520cd837fb8ccea849adc1b36d7e4a2026090b 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 b8a64cbb5dea06bf4603891bfd55fc78662928df..b0e3b9a0e4888ab3a56fa6fe027b280e5e85ef65 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 430c14b006d17b71854ac24345a5e90140e8fdf1..a433ba01a317501036d5492160a9d0d4462fdd17 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 c7c99e18d5ffb47fc5d11d31ead61c0e5ce11ea8..31a7d12db705243a7f3a2d64db39a8d315eab285 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 4dcf7f5525829abe3c7b5751c91370fc9fb5f269..91d43e2bffeac4a1553518a37d4666b30c0cd00e 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 5209889765add4f4041b1775413542449f8310de..49a29338789b74962a34c8db20f6c9c077204897 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 a1cf6447dbb173ecc5bd369c6aa4ba6d6677b965..cbd6742eb4238d227c3bc7690ad74528e808cf19 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 c28e37a344adce0e6785c0d0a9802ff1244aa719..ac0561960c52131d640c44f8faec0489de7b6eae 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 7d8587eb65ffdd813f42f58662397ebf2462fc2a..779260b721cae8a798582215676c9e508351af5c 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 3587103afe59e6e8d283576ff31d917814942841..9085d1142fa345d81467e166bf451131a5264ab3 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 9143c7babcbef7d5158e1f225f7f10da80e0d79f..6c89e3e04cee7f516b9b348ce702402fd23f31a2 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 95428e05d21244ef7f88b00c0568b5b3dda0809e..8b505e1556a5f8b3cd3ddd453cbb797b4470e621 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 fbe5e79751b30392305b2df67cd051828606b11f..5051b38fd5b66d453fa868c97f64eda6cabbfc70 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 e5539e0f8e3b11b8afffdff5f020732fb150c72d..4c1ca197e9c5f213efce54e66655fae16c00524b 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 4eb9d43578b4c3ead533bcae6030ec4ead92ce95..17d780794497153cbb6935b2e2e81d1a7575dbf1 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 a53a040d00543ce3938b1e2dbb850fd629858aa6..b59bad86b31e5bbf2cd15f5835d855e8111b66eb 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 dea637a09246c2f7136255dff64b00c8558b7155..11c6148283f3c7a05efb616d68b279587ea70d66 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 26ab6f5bbaaf83594aa8dc3d58d4889368b3d830..e9f5d62e9817c442cf9896a3b673615eae2d52d1 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 22500c3be7a94b460704b11f439314de7177dc12..1599de7305327cbe506504e229232c4dc1f50aeb 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 d39075b1e3b71275df203063747812d9bd49c305..b078205b70e0b576217da42a5dc2991be1f21795 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 273130cf91d1203ffcfef0662b515cc06ad1c066..d2daa206872da406408a2685f6659c312b9aa18b 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 99eb5682792a30b948e02b1e0bf64b46789a613a..d7b282e9c4d51deae49b5a71d3af9b15a5c4958b 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 a9c9a94c096f7f44d23bf63249a080f67395b3be..de58e976b9bcfccd8a1dcf8caf92ad294a07346b 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 98a5ca43ae87001c67b2b3e38304afb371831f2f..390819947c37955ce8575ce4dc7aa921bbf7fc26 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 ec64834b1c6accb64a8f45ec728c63f4bf08d48c..3f0903bd98e9d663be263e973a37d67dfb33975c 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 806350e1ccb6f7be93e44edc0a49a2b4c9c53944..5fc701ee33e34fc19371496355aa0b5ab602fccb 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 dce10b18f4bc5240b56928277cb81660dc104975..9df2d1cb7a9e42d379b7b8e0dc90cce554a319fc 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 1285e5abf669db58d94b0481f5f5aed9958e2d3e..90b4732972991f21da264bc9c1a9344514c6cea1 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 629d1ee05599f75083d9e22a69ff9237e6421da8..1cee10091b9fb098e5f09478465168bd4ff2393d 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 8e790ec219a5fd5be0e812736ff7be167a5cd20e..ba15d53c1ca7eee3d726089fab57155e00a57aad 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 26d1eb83f72a1791393514721ef3916fcc5087d1..0cc5b611a113fe9f1942a36a5c96a192155471b3 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 5ff3e8af2c2056b7fe19560ee2ba1ad7146aaf2a..e78c7db878018ee4b424c8a49630aedae1cbedb9 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 f4fa8a9d5d0baa1fbf4aa2256756c47d0ccf06a5..2ef31cc8c529541074a70f5810c80e73366d8890 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 a281e61ec60c55eda5c3ec4ec527863ec5994012..29aa7859bdee458a7b384e35273d47ba4dfb9a46 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 f8b1ad2c38280c823c103b5d3f6326a340c1060f..e3633795fb2220875e37e9a006fbffb0d0aba20d 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 4fe9e7fc74d37d8a5af686cebf7d4a21d9c38b95..c78da8eda8f2c8b565a2f87a6a6e6030eb2f530d 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 0bb5663156218045f025e9ba3ad1abb1c18564fb..4990d26dfc733a5ad80c82fc3d4b32918c180288 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 3eab6ece52b44b25d156fa11027d69f8b0efbf88..6e0a3b43d027a5696739cf647a28cd530f8edb80 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 78cf265c5b58ae132d927b1b0605abf939c0736b..332eb352586769c370471204aa320c87c8296927 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 b2e84d113f2a82e9fd9d007b0cf7b437c2930ad8..219be88a59d207c683e3be85ebcabcd9e8174393 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 d6ab5b4d15e543800a7a7524517b495fa6305074..e901b0ab116ff81dc8a77237f68afb9fe5948d35 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 19980ec1a316e8dc80a513948d5a5dff7b48fbda..2a8e0b6b9805a4c5f84ca4b2bf0c0e4ae74fcc02 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 d213ec5c3766db0dd5176c951b13e5f3c1514cfb..f0b0c90dd398246eb2882050d69c6b53ccca11af 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 99ef8b6f9a1a5abf2e89c37a79da906d2103b66c..ccd32013c47a21360c41653a3380429c33026911 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 309b6b9b49d4a92d74adae760d852a9293c9f826..11472178e17f5b45f6de5dfb20a8987cbba75a2f 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 7670ac2bda3acee8bd840a1e110fe790d2cda438..edaa30b208410d5a5271f6f0e17302798cd380e7 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 5169b8cc35bb2d99c322c3e607d9813e083659fc..82caf01b63dd964148bbef9c8a5e2d920b802d4c 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 7cf508f78c8cc2e5b5557c7acabeab73760e6237..8eb7193e158dd8741beb11eece6e5f11ca28b0dd 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 f78801114ee1ce829837c5a1e3147cf119f6c1d0..259d1d2be076fc3b7fe43e6ee1a2e6086709447b 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 2abf27d7df6b8b8b46b972a52619993075f0812b..4f36d3241faf46e08ecd479e815519d0dc2e074b 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 147cd020516a5d5504caf26b8a643bd5acb89f50..e2feacf921a03abb949e221aafa899d4f2e042df 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 fc042419e670b10199808251d8f7310454c283e2..840e12583b85bac9dd46d0628833e43a12f073f0 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 4992e7c99588f390b6e7faf4badbbd6b20aef9ef..ead6812103063a4433aaacd201912c2c62395d1d 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 4a387a23542484ac2d4ddabbc05d98f3ace6da42..8e409ad448f90aaccb2da83467b37ebc7a2c45a5 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 d6519a3aa959669a9adebf756152c35c2ede95ae..7c6233d37c6443cc096eedf20f11beeae380bd2d 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 924b3bd5a7b7196148e861eb91cab9b768179415..8ecd48d31800a19236e9db8a7db284f65e4a29ad 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 4dabc318adb833d12fc91ee0bed224262a26b4f2..a232e76d8f23ffef9b74bd9d6e7e4ce0da565bd2 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 d6d049ba304526be2974b2c4228b3a70420adbe7..36747174e4a8ba7b19d5fb58ccfae2974f8e4795 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 98f6e4f88b04cef8fd6896d3f81b4ce8c3a76395..9a5814d8d1942ee008457aa4d6cdeef09a33880c 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 dd30dccd2ad5e250aef10e889e150011fece3468..d8001b4bca054a82655b60b5621a6e017711e0b0 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 d583bcd119fc7544c95bd463a96a28622bac368e..7d5cdb3af59435c4dd7fb1287c7f8873c563d24e 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 ab73a9a639aecbba0fdab012948630608a09a49d..aa5a2597305ae82ada262121df14c6e3aafd2348 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 22dff661145a1bcbf5996b7cb0c1fba660a5859e..58265f761c3bc95466a5ac1d7558c903281394ef 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 48c865a4e5dd16c445411c808930c28f2bfec97e..583b9fa656f3f8594165cc44e96c8b2741079cb1 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 4d47a2631d1fb46d9f913b59743cb5417d7401c6..b5c831e79094d40467cf065a7056a3666e278237 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 5466c6d85cf3ef07388e47012b88fb478ac0d5c2..72359709cdc1741beff8656b20f0432895388717 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 e0fcef85b3329478e0ded0188b5fff8b93ca8388..39a24eec88847df83a655b240d90fddde023990b 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 46af3a5e92094e3b529ef821bdfe636608382b25..bb509c2549397b29f03a75a1e542074eadf64702 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 e847ff1019a29628d9e2e3fb71e3344e1f51d3b2..187d39bf0bf10ca178cc3f1a7b45e18b7000ccbe 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 b8e50f76fefcb818c1e82f83435447bbcf1e3228..2200fb698dd0fed2ed62576ca08e2232158ae274 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 cb6079f8a227f4f63aa38e2da493e49a6e44764b..481ad879197b867f2e46927a8c5c5cbf501918d4 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 337718fc8a36f9359d52c1633bebc49eab56874d..d0c6df373f6765360318027a6fbd781c519bcad5 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 132432f375c2c826f259c4938eae093f9d7774ba..eb1ecd16fd220a06c26dc7df1f69b805753aa923 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 d98eac371c0aea071d90bd9cce713b73b13f3127..69536553446dbcb54be8e69176fc95c73c20a575 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 61128b48c503f4ce67093d7d672e4fda141d5dc3..82d0bc3a4d52246f731be6c0e23163ebd05f9f34 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 63bb1ee8258e6fad51ea51eb39305554fc6e841a..4a0b74ecd1deebd90c163f8e440c379921d11e31 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 a470ff0868c58e1d6f8ceb88dac3a6e5bd0f0a1b..e08a12892e8ba8275addbc9f9d8c98f4fa8051df 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 c6f4982d5401403174585b558be2829715e56dd0..39001a401effb6f94f4d5e82ba93827dca8f05ad 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 1f67b1e15bf6cca947d6c5a7b0cc1af248816f62..44816ff6411f950a72e1923c676f82f37890349c 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 17185d73d649b9375044442d887662a4e411f24c..ee6b0780bea1c34cba03c8353159d92de8270dbd 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 b5420371d32d0714c3447f6ff376b50f7a1a0ac0..6dd25dc5f0279a420aa619662e82e7586ddb22b5 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 b393eaa798efd33588d7e797e0ab22fecbc5358f..2e796b54cbde1453461a42c7f8a524eb45159c78 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 0c7dfec4acac8e55c6a418c5ea6b6269786b4a21..20c389a91b8033c1a8f134bff08dd7ada9a4d9bd 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 13da87918b4f3288d1e437fa0c97390ec6a6810c..532410998684d94c59943c065c315b930b48ae0b 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 beb44e22afdf7243c7088e40b25571a2d4c54bfd..f6e5eeecfc69cd2d3bb8644f2c5de4ae7ff8f6fc 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 95ce9b5be41124cb6f48db15d433a069fc76f69d..0acba2c712ab842b98e7b1f005e89f0e206555b3 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 77d81c1a63e96fdda212add84750fc59259c80ef..802ee5bba66cab996b945c7463880706cfd0b0aa 100644 (file)
@@ -58,6 +58,7 @@ static void cpu_bringup(void)
 {
        int cpu;
 
+       cr4_init();
        cpu_init();
        touch_softlockup_watchdog();
        preempt_disable();
index a87f8a308cc1bcc057fd05765a838867399b44f3..65f05776d827fecbae83a0552dac4324cd255847 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 8c24605c791e29e21b6634dd3820275ea793159b..380eb619f6575f40f57b46d261e7f0573a5fb372 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 8159f0a669b8dfc5733a9dc2e7f6b16c02b19893..49b781a9cd97974dab36ac6971e82a5271cb4d0f 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 39845183917866afbe2707d0842b0a3615df6575..d696f165a50e6e815deef12dcc0b19d31fd22494 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 7def63ab00c0ce411f385217d037b2e393faea01..e3974a8f8fd41aa30cc89c0b951a16fd1e2babe6 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 3eaa459ae0579d0c839399874491cbd0d0723464..aa64eece77a66a08a9816505f9e341770385e196 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 bc26b5511f0a9fd3b77ad28ecf18cfc26f3b342d..38a59a630cd4cb98badec27818949d75a206813e 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 ce5603c2291c61d5da1d8b45d9b2db8f97a90634..6d79a1b0d44630f79ac16df744e2e9d758165e2f 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 71bfa95f8e09bb95d45817cf92924cfa9bba7a76..db9c1b984695db6613dc72575159115f6b3097e9 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 9b09e31ae82fddf1df399dfd67f386a321133c15..63c1e76739f12648c9face8e841d756d693dec01 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 0a58e969f8b7c27c1c956004f7d036b6e7b8def5..df3cac739813fd7f85ef02da83504aa0e4d34d59 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 8827c60f51e25a0cd24bfa5180fca6aa48c3cec3..8d553c92cd3225761a78f113d8caf8a75988bdd6 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 b4c64528f13ccab74f5933b89bf718a88e490045..da84a73f2ba63b6ecfa6d84483770ceb32db0e93 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 0df9b4461766c79499d695b10fa74ef8d6337877..994a9074742046edfed5afefe62011450e20669c 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 f7035fc12b92801c8f8a6f2c94a740aa78e55cf1..09f28479b243ac93f1d9d149db3db1f6ca71799d 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 857c8f1b876e565a5f7d1130a10351880b8ecd51..4e5ca632f35e8f12c2a01f83b9cfc58550f1d359 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 38f2da6f5c2b64ade3e091e26f8668607d27765f..3f9e274e2ed325ad1fc59523aa1d368e201acb03 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 f962488546b638e9cef66e0bb9cdd5326345fbd5..62ee90b4db56e9ae30f5f17d365db1b2af67cd88 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 4c1395f8e7ed25d8dd623e888614a37b88eb071d..7048a41973edabc15cf04c11a44063fc0f2b984e 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 7eaaf5ee5ba6ba618ab4114aec1a0be296722f1f..bf44c79beae92b23fbc63b011da722abcc88f040 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 8598fcbd2a170ad669fdc5ab522ae04ea1ac442d..aa878fbcf7051452c1f12cffdca121abe741c70c 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 4d1729853d1aface77da09b151869f162dab562d..71390329038553cf5b56693f8ac7abbbf94c640d 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 167e7370d43a6208dbf24357954817aea98fc3e7..e5e5333f302da7e1550adc6aeaf5468846a59a97 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 caac5d24baa4f0faa5e248765c90b98dd5bbba1d..4bad0614109b5c83b6fce2183b7efdc29c8af372 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 3f06b206247516e23cbe2065ec77289855201a55..0822adc2ec415b9d7806721f0c273c2366bb3af8 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 1dc10740fc0f7ca12ca7f0184c3993960de5f4de..6707659cffd6eeed6df70f88852f3485c301a081 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 f124a2d2bb9f536664d06f4b72172d15a57d328c..da5b6723329a90d5206677202c03a9a6e7eb8756 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 f2a91c4d8cab6074c9a1d1d6686ee1f5daf6dde4..22f6c9b20e9a153d0182438a83ff813cf536c832 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 cf8156d6bc07d3cd9b7f38578d94ac44d72d97ba..305fa5054274f5bb352545b43289cd0a6625be4b 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 53cfe574d8d4b647f378e602c44e663e401b772e..f6a147427029a83bd966f22cc8cd7d72ec85c770 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 ab0fb10b6bf0b2e3a61e05bc2761d1759aef6608..d81ae65f0d188aa4339a4b0a83207c609304fd8b 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 7a9bb5532d99213b4c1e0bcdeddcb291a8d6fbf0..8a30da7f083b09ad2d5d15a338853a0a8bc23662 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 4fa2931dcb7bf0c4e80b20e26f213e5b6ebd3f4d..00b113f4b95884a221705f1d41c9145ddb93a44b 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 c83c8875bf8228330b62806d2ffdca9efa2bbcd2..68a9b73934575cae82e4f41664b788b7352ba3a2 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 22cc7f68ef6e380580e233150baf18daaa0695ef..20a9cb7cb6d346bbbe0426c977670772df49a76a 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 6f5af4196b8d0c7c332133f437a9432878dc4a9c..fa1804460e8cb171d9f44793eeee76a2eb3315d3 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 d3941a735df3f6e7fcef06cd2bb007a23d0a3311..52096fd8a216c7ca08ba43dac24d7ac85f2c6e75 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 bb6434726c7a945c0e96c2edbd10e505e25eca85..7e9f4c9ee87d8da092133e0e5a91710b7afd840e 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 937a930ce87de63d45d7e8d44434efbe62a9d3de..44fd4f9404a9740b06863f00a0357c0f22e68895 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 85ec99f978412fc9c4d18fb3dc3c94c0164b1042..20123384271c8150e969471ee19ac090953207d6 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 1f63b3034b171fee11954ac3a874ddea25ec3f08..7b7b4a6eeddae359d571fe4b4731bfa275502a15 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 7e67b651e4ac9c574115052c854995e7c61893e7..916f26adc5955b8c021e607001558ec4028146b1 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 ac90e85365655807c41be44c9e9c921383e05caa..fd7f0fbec07e63ba0809e63b1762ed9cb7702f7f 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 fe5aa740c34d6fd00d75d06cb77805f3dc9b3ee9..44d314ad69e4ec0e44395723b311c97256ec98f2 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 fd5212c395c01967b8eb53e6045103de20a4efb4..0739f3b70347bb6ad340c216f3e5515f726ddd33 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 c62fa7063a7cfd0f366e2e17ecfc68a408c0edc9..92e3258552fcafefc93c30ccf155a7043d40b92e 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 4983827151bff430299aaa6a7dd105fe2286e956..adbeeefaca92fe93c744d31f4f46bef8e497edb3 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 8072c195d8315683bea64a54c618f0648c53a054..474f304ec109361c59bbd76eb7cf31c8f53a5e40 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 76f37709dd1aeee54e7099b6314a159b08cf849d..b3f7eee3c93f629f155974d1ff0a165191f64339 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 d9ca9554844abd3386322ba9ce830b2a19017317..3c71dc3faaf5b99bc632d86a73f776fbb94cd581 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 75f64abf9c817c6dd88e058a9a3b51b12c8eaa09..e405309baadc199d6f5510f4d0c1e8bf4b9f0305 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 712df0461911592d307b6915ac5038d6ec9b71cd..1118eaf7ee39ce0b42eaebd6a3337af68c30e291 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 1d83f3ba478b961426415acb10b99487a165ca83..1f76740f33b6fc21b11534cb79216ce8cffbe9a4 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 a2301cea1cbb4fb4aefcb15275d1a6e332c4148e..7da9c81759ac044340084ddda74626468c24dd5a 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 d92f5b87c251e1248e20fd44708a4d80f759bc00..f54df9ebc8b305bc057533a7ebf283ec43f7b6c2 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 6314225dbed0a39a48a286d35d7a03e209a1767e..3611a05716673bdfbba22b2c017b113d88e8f281 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 80b75501f5c6a203d7967fffdb94378b89039dab..ad19df0686c93c0cdd66d18543764a4925357ab5 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 c1c391816fa77da72ced9675fb2afd0c3885c93d..639b596a06a9d06ec01f97e1fb3d28e854174f81 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 e4935dd1fd3711b0c1f04735f7fd611c0c7daf62..c23bb29e6d3e6d988ff4493c138d15873af174c7 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 826b3f047c0cfacc38fd983b6a1b307b1944add9..cf25f183c4a71b25ac6e10dfff0a88f7e4fc7f07 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 b032d3899fa35ce412325025c110ad17a677a535..0d695f8e1b2c4cb5771e6fdf28d75af076d886fa 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 c8c6d0436ac9d00e25d18f3ec366ca9635f6ca30..5008a3dc28f454a89803f361c35673b97f0f9119 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 bfcf2ee58d1495dbfed915ba475a3ce0fecd772b..6196217a7d936c6371743354619c3564cd9e0c69 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 cf05816a601f5252e7c1308f13334e3d2a554572..e3b6245bf4b23454423724ea18d2ef3e3664ad5b 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 671a285724f9d807b9114328e82692bffef2c835..185a577c46f61b0fd7888de55ca9e86e526e9844 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 914fb527ae7a78e57fdad2dee7e6d50641c2f6cf..86b568037cb8af6ed004c4067f4d4314d3ed04b1 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 273d784fff66df68bb7ab8166599ca343e939813..78a364ae2f68580913c2e0e589cc9156ca4b8140 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 17ae49fba920f6d8eea99daedad7b7b5f3008467..aa80b4d3b740411ab8159f0c82d683d7c3d24d1c 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 83dd3a2a73163982c74877fe2d75a3f91947fa80..53bddb50aebaf500f0f5059a9fd2cba56e7b4182 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 43f6da35716599be1b823fcdd1670f755433f331..8fc36a28081bbe4b42e2d8beb3d4cff714a87faa 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 cac68d1c20c51bd06a13d699f6e2fa850115adb1..da612b6e9c7796f32202c37e7b2a0b56b6db4eec 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 72d5a7cde7ea815cb4950e328129873214f9ce00..894da5abdc550461fe0f6d9031ac1def01c81731 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 388060ff85e71f7deac3307780faf4e51dfc84e9..f7752a5bef312865660fa29d7e9f4b98b03b0add 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 8dd5b1b8db60706200f80a4ae803d9e6a6092ffb..ff64a39d56def96582571aa4551189cdab3fd062 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 84753680a4e8cab9653bf13f02cbce63dcdb0671..3ea4021f267cf6bc1b6ce96e436305cd834401ee 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 05e120e01cb458771769279f52b04b4bbed4d007..1f3b30b085b9bfcbd7cec9bea9e1f4175fb78498 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 55943b4dcc7b6b131915ce193aff97fab79f4477..0037e2bdacd6b25ea2edca74fa7d11b542e0b843 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 e562a578f20e6f6decc5937a930541624851dc5d..9b3c9f390ef816b699cb8da32487021606e24161 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 6b9056f9483f552e62d8f226fd7fc31e8811fa63..3d9d371c35b5e494c42d9365b32908bb129a26e1 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 58a9574454849ef98c4df6011781391e66ba601a..710c30562fc1fe62ff14bee4122c539c3cd7ad71 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 13a6290c8d2548a7db45e19be1e6fb1f771ec5b2..a7d2b16dd702c9ae4a312caa40888ea6ad7f1f6c 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 fc13f3c73c47fb5da042460e23793cbaad925613..67e6968b8978ee720fd0356203746754977dc728 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 30751eb9550a4a099c85a81b189b85c8f84096eb..b6588483fae125a28562df82e90b2fb1446f29ea 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 2219b93003167ddfd63b767146355977d3307996..c950ea9a5d003e0645be173a871303875cc6a47b 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 82052b6611c9d6b260cef33b7a6d806494c07101..5caa37fbfc1870b236a95f224609aae979ed54da 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 08c9b9f1c16e9e0e829decdbeb120fcfdeb8b848..54c0ff00d67fe731e9cdacd6ae8dcafaf0dbc566 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 9bfa228d0eb093426474eb1ecc1386f0dfca1bdb..25aac40f2764aec4b3223b46d6d3919773b8b4e7 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 cc6aca6e436c8de4907110b707a83bc69f82780b..b637836b58a18af3ce4177f3d6b29ce60a7c2824 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 5487d4a1abc2a1ce4397292035668cab7d2784a1..14638db4991de8e922c8cdb26979a1989ae47ec9 100644 (file)
@@ -4,6 +4,7 @@
 #
 menuconfig CORESIGHT
        bool "CoreSight Tracing Support"
+       depends on OF || ACPI
        select ARM_AMBA
        select PERF_EVENTS
        help
index 3b435aa42af5a5370fa50bdfa43db0a362dfbd65..3c0ac421e21117bb685009f5b55b2e37230d4116 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 4ea68a3522e96b17be923fc1fe7e8a397a5a9ce9..16ebf38a9f664a3676188008cf42f5c606228b2d 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 1d2ad183fd92d25932b751ff4f40342c17cfab61..80ceee3c739c88c4cfde80906566f1bcb4e84f57 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 e8819d7509387a065842f577c20781757e0a94c3..2463aa7ab4f6747a7a04670aba38a202ecb3e77b 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 4ee4c80a4354397871ca8cb7368050f2daa4e1df..3810290e6d07a1044b386cee199eea243afc82e3 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 3c629443274876823918dd06e758fa5ccce00988..5c1ca0df5cb0064d3e0c633805bf42b8ef00622c 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 79e1ad860d8a00cf0817a72a39aebc3c38cf4c5a..f3ab96eaf44e5446e389d64d7ba836be070198cd 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 75487b3fad86b4db5af00774609f57ea1752ef50..e8c7649f123e735dcd17219535a148c52922bc60 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 be302ec5f66bdd0be912fa31b7c922d77bedd1fe..e2cb6873c3f219a6d937a182758b630ebc6da305 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 8bb0092c7ec2e7786a5fbed6b79f0c55319050e1..7bcac8896fc1d7f266176bdaddbdfbab318ed73e 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 52786e9d89264b00a103a924e7b0f75368f428e2..4523f10ddd0fd038746ea788e9628d0f3d14a4e2 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 16b0c0e1e43a07b7e61e4fd15de06f7c1d905756..fa97cb9ab4f9dc6ba8e980fbcace0294e3a309f8 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 e0684d06e9ee9b0cf1a139cd84742cc559358d2b..7d401790dd7e102a31675d8b1b8baee411661708 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 8c9ce74498e190486e2ffcb08b28c7ca7031c9cd..b7d6d59d56db2a59e9b25ec4b9bdf8643edfcf0f 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 9f8a844ed7aa304a40ab2b57750d9b8b1462b05d..b908ca1046452c967dc992b8afbea861e3498aa5 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 2527b5d3b65e96203f7a7c0387a34d4175ccb6c9..23b7ff00af5ca4bf32eadc7cf3ea640c4a1e5f9c 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 df6e4b0b84e9319eb32a7f91830e9add166ce46a..17006705287a525c697d9970ffed9f7e99aaef6f 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 3f718729d741060eff20002cdf78c74655983e21..be37aff573b44a225de50a1dd36475cafc1ecfc5 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 503f1b3a374130a72b2dafdc6907a77395ffea26..1ed50411cc3c34540fd1f7ebd3759241d55741a4 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 63d9af31f57fb66eefd416144a70a355bd8632e1..f8583e4032a6880e0cedbce384bec5f6c7c67e3e 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 4b130281236a25c0e9ebaac850ba5ac1f2ac0a99..55db77f6410b04c2af25e822a9eed3b3f3f53b59 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 033dce563c993ae4f859209b9d4a474da9cf074c..55922896d862686fbe64e9ea214f1d15413f1797 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 81bb54fa3ce84679c4adfae2a1daf780999d9ba7..8ab28e5fb366f62d18168b0d0b8fc305df85cf9c 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 f1228708f2a23dc179dfa4fca3515efe4b8dc818..c0378c3de9a41a7ec65b994e18b907e56fc3b88e 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 455e1f36a2a3deb869247173d8c3d9bd3808187e..c7fe3b44a860174a936665fbf0e1dfc628f4466a 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 1969bfdfe6a47ecdc96b895e25e15dee213505ea..428a82c3a35fb7e0d8f0815e4f234f36c0ba9a4b 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 406e5f695a7ecb6b832ae29c3b30258afaef8fe6..2eb59a260ad469c37a10757a237242f64df07eeb 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 1d736a4952abb0a1723a4b88968300da0eb00131..5bd51853b15ec519a30e47995fee85908cb33cb6 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 0af4b289fc63924919515ea4c68bea9da557e98c..c4810c73b2a22d72bf242ca720fdaf1fffd2d520 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 40be7adfa1f2c7b90a9a1ac0a2b95f88e0ed10ec..98d77af8a2b0f9f95e09bd7b64a0e56cc4467d37 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 3b84cb243a87415dd3bb36338bf4b5e44d0f16e9..055227cb3d43c4bb6f51f2611aa57d5fc9b9936a 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 e14e655ef1652ff4ab3de4fc9c267c9ff699985c..3ef7e3a4804efb9ff9b834bc04e332b31591b39b 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 e589f64eab9d61f054a200a5b5714fe40c04366d..6645771aa349accd7e4ed4bc363a60e17b5a9ae3 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 011aeff19e3ecfb215bc92f8fd965a9492a7c218..7971ec1eeb7eb87cab80a01a17da8fa67142ef00 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 274ce2f8bddfcae5a5e9ff3292a8d80c68d400b3..a923f90f6e803e9df51a653895df9615db1ffd63 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 54f2ae91f61432ecba85bf0ae57655b474977a9c..0205c0167cdd6b9f33836001be51cfebd3024b0b 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 f96a7702b0205048092bace1301f2e2563d2b495..7e3286265a3845346d11b82d7d8c2b3fe72042fe 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 659ef37d5fe8f3a0642ebeb3316a5aead59da89d..edc6f1cc90b2448d037174113bbb42c048d77ff7 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 24c70c3cefb4b4c8cdc77cb9c064d240059cd1ca..aba0fd123a51bb714aa767235915639e1b777ee7 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 f9ef52131e742b048d9244a4a2a747ff7ddb6f6f..d8a509c2c428c2ebc07b1329ac043b8897bb01e4 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 1423221c6e065a415ea28eeb56df69d9a920c1e7..2640b75fb774cae659bcdd718967504f25e3a83d 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 d384cf0250ffc7700d1dc14b3069ad0bc08d74b4..a2837a0e7cba42e1f5ec87ae0ebd6cac6332da02 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 d23709ed9049bf68b9a9f5902dca6f675121b72b..32f1c4a33b2085495bcc1f01909aa76a8fc4a329 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 4fe97c2a0f4336b8a135b87c01886c2a9e735fd2..26a7bbe4d534df3fb237bbf8597850dd4643966e 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 70bbcf253cb641eec53ab0f775070a782e5d7ccc..7b28d045d2719f3e3a710eaa2ffce0e3183d561e 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 d1759c804b2694e98c289f65b1330089f56916bb..7bbb64ca3b3248cbf840e5a9606e0644c5a224bf 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 2c0d0316d149707f96e069b11711fa2988ae9fa8..2d685730f8673e650e1f32d16dc22fe481445438 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 2327ec18b40cc1f43849d38b8f82b9865bf5f367..1f7ce5186dfcec7541c4b5462f0db7aa3a8ed8d4 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 19adc2b23472bb077a5bce8e563c38e19da3dfa8..ee1e0569d0e166b5ba90156a3120a7d699d921e6 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 0a4d3746d21c34b0cd3a23b1f4fca8653e7168e9..26e2011c5868906e596d942099eea50f0c9a2ef0 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 8708394b07254b42c190675c4beb45f09e3f5794..5dbdae4ed88183961dfe549f3fd0405209238603 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 7921f827c6ec4747511d6fb0955112119429c44d..bd72727fc417a7cc76b9b46ffca172e4f7ad6f30 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 a09e7f5dd8f72d51c2f13f371f9c92e1f066e463..f13c6248a662f9bca7110bb6abc5cf84e9191ad4 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 863d73519c0d71f0296116071184e88a001bd75d..da7f126d197b412605baa0adc281780d5f07e408 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 3d6246f8642933bcf069ceb55827e8a27f0f3f7a..0176d3d8cc9cc40314f1dd326e3e13adade46d74 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 f9bf7ff7fcafd3ef8d5d48ebcfac87e525aee67c..bcb58fb76b9f7309375d8530878c73df98ebf4a3 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 7c2d6a966fe6db337f46ddb3aca9ed0871c83986..e0a33ab66d21acd32f5700c8debb4be7c729c6c8 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 719a0df5aeeb1b7d812b49349eaf8e2ebd9ca1dd..130362ca421bb2b188abcaf8d80c79c882944224 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 a513c70faefa1a895fe183aa2ab482be0492da30..475646c82b40e2dd61e5747f2c687c198b52cbcf 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 030c51363ad8659e36b9bc079c1d5fb1e18bf73e..26d206681472e63db674b5549a563c1f9377ed67 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 c86db8b42380f57a2bad08790444288e52aeb7fa..240b815025127412f70773eb17795899201fe936 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 f2e396d40dddf8bafdca80a6668551d20d8d0894..518b1e50caef11cc9f8a8e912e635f236f566c96 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 9691524ce5b037afa5895813bc65bf2c62d03f70..a7322184cbdd0680cea8352efc40ac8311402c50 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 4e22b3c3e488e65a3f3d34188d48019e77c5045d..b459600e1a337e70c5ad88e7c07fc7457d5f1ac6 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 5e461f0e759c8ca0b78f87d60e533c7b706d3860..c14bf533b66b39b06c422d0cd4431733c89ba7c9 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 fd95d924a9965926bb1d2b58abde809bc4ebe957..a6702a74570e206784c250758ccec14563436af3 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 966d52a4bf1de8f1eef31e828293a1f8cd55f258..b3211e0ac07bf2ecc272d3d944070386d6c36796 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 24e4e50414e6aa4e3661c951375e2547aa9cbf85..c9d3c4711018f1c7cc4790783d18da3933565517 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 401d7ff99853543827ac6b2dce7e763a96c0375b..524a686077ca6d3f3b0765e8cf0c0b96d0bcf6af 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 2fb2314548e9134151e854af1dc834e987437b8a..5a8351c9a426591b9374445b4cc1182aeed2c2f9 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 340d64d0ac59c8b3e70c3d54802714a4bbb321fe..a8361006dcd9bd3a4f1c4f25ae82e6d5716d8c9b 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 eff7ac9ae66952fff6ed0e3aed58e1b17c8dddf4..b955183edfe81f2b9470f8c26a9042eb8f3242b4 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 b191811fd7495602538f6656423512fd88fec149..ba420e4847875d8f448591d6ef9426558f63e781 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 c2058d7b2f93c540ed03c94f1e5398f5ec50908b..d8f5ace1f25d23c1776fb708b7c1128cb343a66e 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 c31b9633f32d9b8bcac8d05d3822230d7725f5dc..c613a64c017f1e10f67867a4851e423f22a5e64a 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 829b0c6944d842957fa1bd5026fdf01763bcb882..61758201d9b26474048cb7a24b62a78fec9ddd2d 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 e068a02122f5e3e5054d4b9b402500f8028c5e6e..3afd3e9330e7891e377bf320c9709228717d7aa4 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 4305da2c9037f0185e8adc48db247c6b4fb5771b..d5cbad2c61e490a4096669e5a27373089378b9f0 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 ac21c050fdb0e4d121e34c070035b0dbc6d20386..a2b5fbba2d3b3983a875709a7a8b86839949816b 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 62dcc5b71641cbf2db89a8a6392c2fd6f5a582ac..f002fb88f2e75e96616d9e8fb648215c970eec18 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 fa79a49d7ca10b95bf95ec6703bb837ec20a210e..dbbe7c04010dc240fef3fbf70959f7a28c9cb602 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 2ed7da7d1f3e1eeead2fc882b8ce6ff68ccbcf69..4cadebd8b9c46df56dc386a425b7755b5195edf2 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 55f5b7bb4cac9284128892670ea626f4d62eb6de..9a5f90da06ec0b2ae943cfab181acdb4d4dde4fd 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 42cd9730e4cc7efa7b7a6a4a66a245c8157fb5a4..b313e38b2c3a83436a514a7a241ec84d174e1052 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 65a4fe26324fe752b7fc55100876cbb947ae9744..bbe31e0b759fcfd032bf195eba6c7f8b7605f03f 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 f1569ae8381bcb8f5a9e044e4f905c09056367af..ade376bfb79f5b5430db68741c6fd9068a0007c1 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 f1681706f5266803f98a62e1258e03bcc91a1262..9cfa460466aa783fb11f76e1b3838fd9a5fa6eb4 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 d5600118159835321c3c55b1d10e1cf4468cc22e..38cb6d82d8fe672e1d2b6b7640b91b36c69cef3e 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 a23c23979a2e1ab792e28e51a0bace4345e1d563..03f4d152f6b7a298ff6ce7390c55e0958dcd664b 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 1eafe6b848ba51f5cb04763aa9ff5cc90e0ab42a..465eecfa6b3f0b95476db3810a998fca91ba51eb 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 ae9c51cc85f997b92a6581a74a0ba65f6a673cb1..97500a2de2d5123a7f1c7a9dd40abdcc54ba4e3a 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 6da607d3b81172a38f95c672e37976bedc8d097d..3bbd7e6525331924df5ccf87873ef2077ddd48e7 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 9d39679372c5ae350b6ace3c65d788f271e3daf2..fd355cf593979ea5eab2f9dca547d9f24d5aced8 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 fbf6caab72179e956eadb2ba47c65faa4b48792a..4d875f2ac13d6720422e03cedf8011919ef5d5e3 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 420efaab3860f2f4fcc96bc47566d14f146b3b4a..d9b103a81a798e4a22a224504c7f7b445d6e68a7 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 a4345052abd257f5611d2de0b7c8e20013f50e5a..2d8434b7b62381a85abdb28daba2391fdd117e40 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 12ba5af931453d1ccfeba36fb0056dc845099de4..46343998522b047cfa9b0e531a935a1dc5a0ace2 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 b8ec301025b7c7a88b17dff84925234f97d4077d..1080c0c498154a789f89c42e4854c1307eb0d4b1 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 bb14369e34a78cf8a4d321384167fc58db9e6adf..d20a5d6780d1d40b209f40da0c9342493aef9ed3 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 19378f200c635706a3f8388a31a8b81a94281792..4a5f482cf1af5550e6f504b11c3bdf44d4319b67 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 c639ebce914c07fb936684bd37d0321e51250f0c..3cc4341bbdff6e5ae8305b237331a27f98816ec5 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 c6b85ba7f991fe5b43ec1d4b901df92fca31d817..2e1404cd09ec9f62491f082d9598b8d1c71e1ac8 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 c10fc594f94d9b6ad86b9faf32c8be9b63b2474c..e04eecd65bbb0ba802576bde4d5892c91de2a6b2 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 4f6fe8cc8efaefeb8cce55f52251c35f1963f4d5..5875bb1099a84e1741e0a70ce6cae78662577aa6 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 2d96cf0023dd7660e2f1b727be5024a562b973fd..a9a9fabd396804a26b77039d0fe804cea3dc56dc 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 653b6b3dcafb0f09387653b898472694901be3a0..64977c131ee62aeeaea4865989ba8b378c924aeb 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 f802255219d3ac942f290ded71815b05d447de4b..a7f9c3edbcb299f83f8d4c6093c274a0bc5b3387 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 920537883238b5521c074578979d17b7140fa642..75f83ba774a4f6224997868dc6ce9b3266ac2a24 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 35500801dc2b574cef51de9e8cfcf14d4adc57c4..730fbe0e2a9dfa788b3698cbdcb10b682fe22888 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 b1f19b210190184f0a01d1304155d5ed2abf1590..b0d46ac42b892340ce649ee14acbd42dc1f0ef8c 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 a64116586b4cccbfbe6b8e26c38209eb7ac5cd10..43b336316fded7dc80ad92812bf9dc96d6accf0e 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 8513c42f70912e3f560949dff47fe469bd6e49ec..fcb3b18a0678e2c1994709e343aafacf8eded0b9 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 2a48ea3f1b30d4adfc6581dff3d1cfe1a088b86a..b6b5acc92ca2da725de6a7b0f867c7c83b77d464 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 1b16d34bb78518a1849aa331c6da2ac1da0e8586..d5216bcc464960b4fc748415c1c8e32abc523321 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 44e76cda087aa658fbb13195fa5d91f4117902b8..b1b0de402dfc36eb937cc1967dcf4a341057b576 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 e549392e0ea517a55ec672a95a909a8082d19414..99721c76225d832e8de333a722c6a0ab78ab7a48 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 5f7063f05ae0771e3a8ebaaf697da58b9d4308d5..c9e44ac1f9a6d201de99439ad2dfb91b4373e75e 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 3107f2b1988b35f3b22f8324becb48bdffe3bc13..63916e1dc569caf1ddc2e09fe85e1b06803ada88 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 7f0840601737f473dfde9bdb06de8fc4f639d264..4c68a7b93d5edab9192a3ce9c24fcdc79b7e1acf 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 392ad4f5c57070957ac0cfdc9f9b22997840bf37..dbdee02bb5921cd6638582c46062700360912963 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 698da973de35195651117400e16c02bf785391b1..2a3f7ef1c8c4c7d623c3c8b2d9f9743642203075 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 6cfb293396f2c4639c08bd11d5b0e744bef1d596..693ee73eb2912c05abdbfbe4955757cc767c0731 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 d8882b0a13388ae213bb869ca782bc61d975ca65..c2dd322691d1ff645c947904b04a7d3dca4174ac 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 8976f82785bb8850a352c2af5468daacb99e8484..2ee14d8a6d318f4ed77bc8155b192067c3441c91 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 5d5c41ac3845331218ce041aea68584605c4c242..2a9ac5213893ad435c2a5b1cb6ed6e0de85a614a 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 8ce1e41d632cc5747996091971e176ac251db76e..b65e585fc8c63453bed196b53bd33a3333bd0835 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 85fc77148d1960cad79cae5fb72627cb35d085c2..6abfc8e92fcc14b2584cc7baa7e2d4be77cb5243 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 b9affcdaa3d6ebe32e383aa8e6cb0288055d47e3..abd8ae249746183ab75db6517eeefa1f6e320d2f 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 b34863544365e3620784d606e3344787d93dc998..6c4c6575ec31164509b1984b4d41769237dc5502 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 192e25094bd47c6195fae37fd4df1220c27ace0e..e20516ffd91e8d717d4ee3b5ef057785c18c506a 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 3c7356d5542354b9270a23a76f0d4b26157d8e30..a696d7509024fab1ed7c322434f9f15a7fedf590 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 f1d9a843e36150a0ee1af466f94b4d53dc0ace97..39eec9031487d343516a52fcba7d8fbd16096452 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 a73c9e669d78febeac33f78417d9d4eb67f757a9..5dc0f6093f9d92aa267c1f733cc39c848900c3f2 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 1fda22c24c93eeee183cc9d9a62b4b4ded41094d..7b987bf498b5d0040c3e068d464d62e695064aea 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 39656413e70dd4e1acd87c01108640b4797e0268..be70b263e2713f49de41e22ebce834e3cfed4cc9 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 be3263df278a917b872d5ef825fc1de7bf30c1a5..6f00c33cfe2291decf4be460b7d722b123e89351 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 8a4659518c33bde32f859c5b21ba89903e7cf543..81c70e5bc168f491b84e3445fa71f89a0b551b3c 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 a8a608713d26d9d18720a70542746fa4161a214b..97f64bcf9fe032faa0bf080141737afd2c0263cb 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 ab7f2cd21c93b3fdc690d808d55eeb694a4f52c4..1dc6c7c5cbce929d40118cf1a0fb7213963744f6 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 2f6dd2f379424306dfcead371ab8bb854a3a1fbf..0e902977d35facdaf1688b38a6e5c56ffb7af4eb 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 49c945d0c4885b7fd0b468f93f7bfd666fe989c5..1b5b82e6526877020d5cfc78cf789c5876f33c51 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 3bc51f19c73497f4f2a17d710dc0daaadb2b2588..0e34c0568fed1adf910c82928478fc17ae8436e9 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 f54e7971a762f3397ee4c75a1d2f2fb2883658ad..2c01461701a3fcb6f3c1af2f9a9024ec97ac1aec 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 6fe785e26859769fc934d5ece519a0957dea0745..6ad83d5ef4b006759351962d54795b724e0dc590 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 f4c92f110a721d045ecfdfa24bda5c0bc01ce8df..8682590e3f6ef14ee397e767d339d71eeee00e2f 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 ba418aaa404c5a8258f769014fcf89dbff343e4e..18e499c900c7fdfd0cb5d0b23a68189394a6ca2f 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 0b19d3eefb98f1a686cdf52ec123794bca6ebadb..0c4894dd9c02a9e8c5e8ac648d3052715a6c17aa 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 eda5d7fcb79f269e1d01065c1b34d8080b75d5ca..cc8168bacb24b3b90d2c8b7cf196246e8f1df7fe 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 02d116b01a1a25a84696fba053fc5095533f4731..75294ec652577f9939b35fd90e6a78c37ba6cf99 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 c83cab0d641e2df257705ac12d7ade7b454e5526..f8c611883dc12b844465b9879beeeb84872c6c15 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 d95d1b2f860d865ef4ede02938c3e3eb077e83f9..d6ec12b3e692b0128f8d7f1ce0e8a665b32ab28f 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 adef7d9d7488ac47a3068e8e254c446becf89e36..10da9940ee0dd1ac2cbad4291dee1d297897877a 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 5f4d155be767bfe1a20da4184581c54d8a1809a8..6f6dbe93f1dfece654092027b0f8306ff55168cc 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 b7a0eecf6b6c6a29680a07d10ff012d3b8ecc889..07127576b3e84df0b90185b3677a79ebafd755b4 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 2894d8975933481ea4501ffcdab156b70a79d8cc..e3b5517897eabf1de40c28d54b28dd540282d5f3 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 506e71e201e10dc417c1eeb32d3ac3a41e901dfa..19b0f0ef1d0bd7ea7196f7219562b6ef53c5f8bb 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 693877e37fd87d45d45c4539aa3f7219ce363cd8..42d237cae1dc571419ee1a107960996b2b6f3d85 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 10aee314144462771fe84455a325e98ac84bb892..176c315836f128d00acab1a6deb42e97e00aeb93 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 0e78a04d63f45286ad957e9094cee43df575883d..c98d88c7a5c696be809e91878c3a689baf3dcdfb 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 c900ab15cceb395bdc06f5941bfc87b62d1993cc..25eb46d29d880062c673ae3f4aaa9c2760a01cd4 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 3431a825f24e65bb9b894dd56e86c01a78db8226..c12406f610d5546b51c5f662480f58c6b5b44e0e 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 4cfad45229c82e285618bb5aac7a7aca7e7a8f94..bb2fec4b5880bfe792018e607c600cdc86a0a862 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 951c984de61ae9e85af22eb05e76199c5752baa6..fb10eafe9bde74324bcb4b008c906dd9175151e8 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 d9fcfd3b5af0ad27ebaaf83ed870083aa3525ffb..1606658b9b7e35ce307c25d3dcf770ef3620f6d8 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 bba49abb6750617ea8fa63e09f913400bdf397ce..66ae6b2a6950caa0a86d55f398cd43170651991e 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 65026d7de1307d32b9e060358dadcc04ef0bdf56..3c5cec85edce22448cc1fc5394f75ba467ae0161 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 23dc565b4307af16cb1fa477f5649a41416446b8..6a284a87a037c80f60f354314fa4cba3049ef995 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 0970142bcace1da555e4dd00b26885d3b2eae952..a26c716c61a121fcd299fb858ff62f8b1982fe64 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 b07000202d4a1ad093b67523422078cce34a142f..ed816939fb325e1a21333fab70269548f64904f2 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 ad02097d7fee564523ac364e4798d200a7aeb45e..f894d1f8a53e0e248c344a8b4124bc783926bae0 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 fca832fcac57f0eb0122fecc4cc65dcc2eff133b..f71a023aed3c91616b6bb17fe8b5a32ca5a6c9b5 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 bf7a60ccc66cc859c6f373bddf5cf20fc2a8c579..3ee3d24026340bba97a5c565832c359c5f655b4c 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 8e3f4589f16d47b707a5578314f0deb96eceeac6..2fc9f4bf70014964aa07e95473231e0e1b53a518 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 7ef8efe9552fc3343cbd9e24b2fae5f0ad8ddb94..8a8e4167750174a8d7ea3a51d736fa57974d170b 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 a6820480105a8e3b4635bda80a3588c9d102d20e..8fe38e7ca6e6d389ca3ff3424a11f2ba21e2ff9a 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 490e3bdc19417c7e2b130764ab630e3f51c01597..e2278bf9f11d4904d98bd47253d4ee3488bb7517 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 ed59cd75e182a1401724b7444e4233cabbac9712..9d4f175f4dd113bc3da823d5d996232e95f2b1bc 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 7fb6d39d4c5a9c88b15d8004f810f3bbe931bf43..1916fa65f2f2a6cc602fed81a983fa608a21e895 100644 (file)
@@ -5,7 +5,6 @@
 
 config OCXL_BASE
        bool
-       default n
        select PPC_COPRO_BASE
 
 config OCXL
index bab9c9364184e031c42a6e50f9f4cfaf832140e9..994563a078eb9f249b8576ddb0ab69abaa4de434 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 cce5b0d6450592bed691383a64bae52d66d496c9..58d111afd9f6ab5217812334ae2da26c4dc01b16 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 3eba1c420cc0831897c906df4ddcbaf0b1010213..782ce95d3f17283700ce99cb8ee3ceca6419a702 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 18ca938b86e6d723e779e6dcea943cf7435f0f9c..a36ed1ff5967f079d983a2853202eea8788ad524 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 5b7afd6190fee6b932d3aaf36449fc76fe4d38e6..09db397df287cd5a07314c18530206e42e664ede 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 ad807d5a314109fb813bf911ad9ee882444d7b5b..97b58e7ad901adfab306cdf62b15364cda21880b 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 300ed69fe2c7468247212c01281a57d576cb7a72..16695366ec926dd76d8239e288cc40b9ee408ec4 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 c527388f5d7b164b9bcc3f6ff4090abbf87d3bbe..de7fee7ead1bccbfc3ce1faa052b06b521281321 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 bd1559a548e9a61e14b087725277f1f57d6ce96a..96193f85be5bba53db81f9cb2cc1a199ef900765 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 2797771a5fa8b033cd6a8d0a28f3ea502cc2d2be..09e0c765946917e77517ac41cb0f114152abee70 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 b27df2d2b5ae19ee7ee72a7a5aa0a9c8f8eec29b..492dd45963142b72ad359067fa648a32a533b572 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 3557d5c51141da7cec0d961947d54dbeec7390f4..e327f80ebe7048ea74ff70a67cfa0e350b15a0e0 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 712a7742765e992023e804544dbc987f89e99521..8dd8fc32eccafb748ce4551fd55199d001b987b8 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 9f54a259a1b36ed4053d56c1b6c5e054386bfd3d..0bcc5e83bd1a0b6774635d37d9cab881cee869b0 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 931770f17087c420251805d09e9fbcf964d9133d..14d89a108edd2274c264fd43f460e90d91123223 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 e481535cba2ba90c51056328b2aa34deaf39bba5..1aee485d56d4c4a13b9b899f1e1bba88613ac1cd 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 11a208cfba04a2992343af7e7ed2b0fd845b0817..914e17bab3bed56ad1baccb0554a0b56a130a63f 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 392a1f87c638311bfe3ddb5047507061d5ce749a..9ee0bc0ce6d0cac1f9d77c89ed7cc4d7ac4ae0c2 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 b53b6b7d4dd46abd07c4955fd13fb310026a309a..faaaf52a46d278409c2f183cea9969f75f90d069 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 fb842255de4941081591194192205c7c55518e5b..037311db3551f2ec98318eaf1da1b4196b09da3a 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 5f8d57ac084ff1217f11e4473e3144e74d306521..64d3b5fb7fe563e0c958dc21e2a8090ce3e0d2d2 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 b1d3f828873248371b99e29b112be627b7f9f8ea..ccc5f095775f36fb75683e867f026a3dc2053809 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 7ca1d9d639c4b60f7f7956432fb2d816ad8d50b2..8b65d7ad9f97de1440698a1d5ccf319f48386e9b 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 5fc76a1993d09348b6dfdde30335eae42d1ab04d..9cf14b359c144f788b6686e799d458052c61b63d 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 68c5866f5c853b64f72f57e5e9ed7cfeca468378..4dd43b1adf2cb70150319a6a680d35768ac33a33 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 4154ee11b47dc59a6927ffc50e06c388f962c88c..4041878eb0f3ab92c2873d0f8787a3f8d528c06c 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 dd21315922c87da795852e75ac24a7de4a9a19cf..9dc4548271b4b25d95c82f035b98f4f62f1e3c29 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 e5dc6e44c7a4f463fe957dc07a98378b4f4597fa..cdd15f357d018be6367e240451956318df83f659 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 9a822e2e9f0b61967c3ae2c703bcc35527d73a0e..6ee340a3fb3a252632b1a714d82eab678173e457 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 781a3e106d9a08d8ee1a6f5f180ad3e248731e13..f4d4761cf20ab4f700e1f4054dc8dfbf9318962c 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 199712e7adbb3dad5c1ab6e306448d6fd32648a2..89fd96596a1f75e18f600761a41302d455124f64 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 3222ea4d584d30c98c63b8d26ef76e53b4d389a8..bb90757ecace12242aa86e43296bcea0c1c19095 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 93e83ad25976e756bdb04408b51c506925b02534..8539e10784b4096186024319c18f0df4e555e435 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 84cb7d2aacdf0a999e6e84fe172de73ca46bc611..2cb3f951c3e2b793761726feb2bfa7a3ac45a980 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 91a2be41edf6196bd9fc7f73262ab206efa46d1f..49aad9a79c18d24aba0d45340964d24b5656aeb9 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 fb31a7f649a3d908989c69149bdaebca24f9f24f..80a6e2dcd085393f788acc823861a5e53d8d35dd 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 806287e80e842621f4560f09e611073bb380364e..62d649a959e28348f9b077ea871ae385cc259b49 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 c8fa5906bdf9a2a3b9fb356032e59a7617cce165..f4da7bd552e93e1c1af534a6e705b799b348c4c9 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 7324ff832b41709fca7983bcd832cc72fd36e120..170a7221b35f10aa928befe40216511a12c7955e 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 453242d6cf562b3ca9e3dde9eb44f35545cf6bdf..408615f29e57608c356e69a2cc703f997ec6866c 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 d759c02d9cb29e57f34967f722a5f03ef077b097..a1f8fe1abb102f8d1756a49e11346ea722b77213 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 873527753f52fc9da5224c6cc317cc9dd730b90f..33310b8a6eb841a852dd8a41349863600397850b 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 6c7ca41354be64f8efeee787d419175e384b9e7c..a6964feeec77d42036c02eb40e6a04c350840a6b 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 30ceee9704d169caa5b9ecf562d02b816e60f55a..9bd81a31e02e8707a9ce58f7a9e563fd0f965d14 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 40df20d1adf518b771e6e5139c8fc9fe30055a2d..334fe3130285a0dc2556b36acfdac767eb137d36 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 a804a4a5bd46a99a3fe7fe01cb6ccafc4038515c..fdc5ed7de083fc6f142b6627ac1ea3a7da4c0cd8 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 0f90e060dae874c3cc48077c596c5d67bfb0c09d..74595b644b7cd7beb619b27e0efe7521ab9761b6 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 aa52e94c771d8bb303e076b90575eae4b75609d6..0e48c36e6ca0d1042347e41451689650a0418353 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 dceff28c9a314c3831824dabfb5cf1ff31d6b714..373d47d1ba4cbae96cf4edc7556f6811d505de80 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 6eb131292eb2ce1316fb1c96e32b81e019ee9b27..91f046d4d452dbfd204ffc758969827b320d2dc0 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 55aa4c1cd414a4a64ff00a8d33c8a651b5078621..17527310c3a1db8eedb0effaf6c766159af1f402 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 fad57c378dd2a2086c66de5f3c03d073f31e2b4a..58511aeb0c9ad424e51795c9e9502a67dce670b9 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 999ca6a66036c82cc277ea9733fff02d02ca27c5..e63acc077c18dba451a4029ac51fbafb008dde7e 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 753125082640c6b684b4cc165653707af7a83bb1..9662b9c1d5a9f992a635ec2cd59eb1efa07f9216 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 4c15bb58c6238f87f823276ec7b6399068edf8ba..89f6beefb01ca95afa16b6d7d44652b580952b63 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 e6c646007cda11dbb2d027c2275aa2715f9cd940..e99d425aa93f57b04639d485203670e4e5fcab1a 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 f24d768eee3085980c30ab57f7457ee8775419a4..752b6cf005f715c8e45bd46bbce050834085b0f4 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 8e14248d2720f69fac22e6724bf54883deff7fde..6de83277ce8b5286ccdbec4dc8ff7f8d6c91b7cd 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 189a15cca3ec34f10dd13043e0ed270069d4fb23..9c5ed03cdc19930630b40a52cd3ff853234b1b35 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 67ade2c81b216448c7cbe207c0cba911952eba56..67f15a1f16fd32198737ed8468a13ecf6a92353d 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 5e2344768d53c10bdac74abc94d5b3798848cab3..b83c4ab6cd9f6cd510e584cbcde5d8ae6e6e8e19 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 0c2ec1c21434c5ea79b36b51c700d7b2cd110081..03cc788511d59e22935f2b03762191e24e14b663 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 7659d6c5f7180807ea4f8ef1f7a16bd170430679..e5c571fd232cc2f220d84e72339443c5176b272e 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 935ac44aa209e9f8753299f01edbc6476cd7d827..44a7a0e885b8dc0ab5b436ea6366a7a87a8ef59b 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 09c16d88172e1da63ab416c6282f88d4ca7f2002..bb6586d0e5af6676948ea3cdcf8c2e1089deb102 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 28ec0d57941d4b756d2673c222a96369072abab5..41c90f2ddb31d6e4471172b2174d5e3e5bd7f23d 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 48e0924259f541425d190dabb4841623987f68e0..4e184eecc8e180c737c620c49523aca605526d6d 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 5f4ece0d5a73358f924cabb34ef5446f9e31cf89..ae27be85e3635aae68fb18ed9a8eee117423d360 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 c50a9772f4affbdb4fc0683dc987f74766f22263..8479a440527b8902cfc6b1b5cd25ef34c6171e7b 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 81caa3782ec058322683afeaf4b04470966ee1ba..3bdda1c9833940c2015c8a18e761f69ef2585454 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 9b497d785ed75ba371d833fcf37d769f53216411..dcb2b799966fe6e112cca1645568388721409c2d 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 97f668a39ae1c7cf2f4160180a8b413777addbb0..676619c1454a9622d8106f7fbaa3e9b116d91d46 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 9e211ad6bdd3df650e17c1f9da11e9d181a25f18..b16dc3981c698749a1a5f85e7066e68c946dfed4 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 afa4335e0a20976c5f1e9bdb5b02affbd1f8f83a..c2ec750cae6e8429ab79ef5d6cf1a7e3195c5abe 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 c1fe4768dfef9445909dafd5ccb438c3cd1493f3..e5c153d99a670822172e2ae11f6eee9aa6f38878 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 c7892c3da91f8f2e69ad4f4fd1bca5c79afce8bc..ac5d945be88a8ea9eab02b85b23a0bb84e11b93e 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 bd016b928589e81b33291950540f5bbfb08e5d08..42d4451e7d678b668a589bf3820df04bde00aac9 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 de893c9616a12df729f748b37688fa6e25516916..9cdf14b9aaabe06a4a0dde1029e8d28425287564 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 3b67896d9d748779a3e274073e55b123fdd10caf..44f53496cab1bef8bf29e759973c3c92eb1f8468 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 89e190e94af7558e9c66e26eee530bd7887d5d31..7989703b883ce64ebe9fa8f58a7c718b6dd10db1 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 04ad312fd85b9a2af8920fb81092b3ae4ca65a41..7801e25e68954e6b323354df7d745c0d4c084641 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 3832a5de4602f0a95895ebcb956a913a2068281d..e6b175370f2eb9f80393cf10f1c4647fa9615563 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 0e8e2c186f508df22739534e464a37b1f3a89225..f9ef7ad3f75d2efbbc60e31646e99aad33c7e4e0 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 5c7922612733ec668f7583b33939752cc5cab1e6..7f4e65872b8daf640886d9887f9be804779f0dc4 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 6233a7979a931d759cba4609a3f9865a2b13e009..ac322d643c7ab25f8b8ab04af94f2da269fa0f4d 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 7a6a6dd3fced956edad0aaa13643858db7397eb3..f5c1f2983a1d1cd954b9ef6af39571be4e35b9b4 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 f435d640694383d6cc7c8d17ebe85faefd51d6b3..320630ffe3cd2c2a7ae573f0c13c133af476a1ab 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 a459a44f6ecda626e9b66365a4470ae2dc67e2fb..1d02e3869b45e2bd4d7f17fce1be2c8eaea42823 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 eb49864a6bad6ac01f5c207da193deb05ef86c9c..e46824da29f6c9191ce18d118f3876a7cd5cd918 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 c56efd3af2055712426db47329ed4bf7de8b6b44..283251d6a5d9b9e48ca00b5691cccb6915277596 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 cd91b4179b10dbf22c8876a539c1d8ff60a576d1..34ff6434da8f897293dbe2edc8ff6af5e8ea51f9 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 1cbf1d6f28ce2038b2cce238867ef582ab305487..bf94a52d308715955f5703365b5a776d51658081 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 8dc5710d9c9876195de4efc8e454afa0e2c8acaf..2926e49373017ba972fb162a4d88b34fa61d5010 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 1322185a00a2f90b28fe012b535f8d93d563b622..8ffba67568ecedc7373e6fbd2527dddd542e1a04 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 e51d45eeda607730e17061641c697dfba4d1b581..6c82f4fbe8a2a27d15b596583ca57bd72c4c3cd5 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 e8a2ba6eabd5f67c84c5b65cac04a552cf3d54fb..98d84920c676c5df0b1e5709ec73f021697f1f12 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 18cea8311d22e3f51039d36fcbcddee8f1dd1f94..0c0df6897a3bb4a3bf1ca3ce56a206df6aacf916 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 d3769200cb9b7bf1e8298666fe0fb1e7f49bec39..f8edd0840fa2b43180fae7729ad4dae7eae6988b 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 068729bf4f8657be05618c4aab58de8d2e4419de..ea8962645e49c0f53347fcfd592886896fb6a1ac 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 73e2c9c0e5496e9bf0d873adc30c9325a978a909..384396cbb22d21a00bf6f71f6fe7881bbfabf475 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 aa7e148b38bb04faea3cfbd971f5f3d8a1d22f14..053101f795a29938ec059a395fcee3b498cbf757 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 4c775b8ffdc4eb582a17df9387148f5d4f3f0b0b..535db3de490b73adbc122402ab6dc3da77be42d4 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 4b06ddbc6aec9cdb31cab11b09e3e74f1912ba96..a5d83986f32e7cb8719ad3be858a50ce0abb57d5 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 97284c3f9e8369c66d4751ed0d6922623f4b83f9..dcf7df797af75a66a15612ab5423f9aa503ea22a 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 4b5cf0e0f16e2dbfcea320414f1aa8c9e8a56179..2bf6af7df7d94f0b8e5c09fec4876d7818728673 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 06b59160783d7985d1c24507971fdee54ed4a265..53a8eab19aad30707232320eb7135d0133bcaa05 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 0a322e2a0fde908e5a2dac53de667584c6658ee9..e08c7992d252d33e109493780811446377f29df6 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 fc38f579f4924f501c89ab4381d17a22d022a1d9..3151f107adc4cfc40885fefd504723fd90b94bed 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 7c9694593f790966c566e58c9b5d01a3e0d2bdb4..c6b9f65f236214b36bd4fd5fa1ce27184f048358 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 8000f4f832a1269d25d6f6cbbaff07f32dfbd5b2..4ae13918316feea8746a2a568c10b19ffb322f9e 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 a64849a9d1b0e462829dacf67404a7d12c7ec1f4..b70df27874d1ddedfb2f16dd43d2721c8a65d772 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 f7e354f85518154e604dc64f919ff70ab8a218fe..88ddbb2e30de10f671cc3d6c144914ee475351be 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 aeab0d9af23e75f559b2eebb91a719004ee7c0ed..5f4058033ec6a9d496d9e632434495ed4eeced0c 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 02020a76bd9ca36cfe28c06abf55a9feeb7157f3..78e9140c13e32733661da356656a79afe343ddfe 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 18d9ad504194788cd406dab062e9de52fca6d50f..e5a112a8e0671551c978e668d912471723f05af1 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 2c7409ed16fae9cc8d668fb23a72f73fd254047d..9a74d5025be648d4c23835db33f0a860938f472c 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 d3b34e9a7507ec6526eb74e61e257039bad2626a..923264d0e9ef2c595b93d559bc04fb209e736045 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 37146caa667d8c8db363c82dd8dec2da77cccb31..3d43771074e6de0cc0d1e108d4148dbef7290b7b 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 d494492e98e9cd933fe0d01874082fdb2503b7b4..3475cd7bd2af35f63a386bf1ad03792b6b823ba0 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 077de592578350ba8cc7f7ac001b33a3016d1c0c..59678692620986316faad33a6b231d8a30067f4f 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 adab4ea078f9835f1f2a500481474bcb6c82fcff..c696f3241a361ccb4efb387ff9e5f608f67b8c8f 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 19e69701747dc1bad7e3cce2f276eb0e0bf75aee..d45c31f281c85647fe8cf96139f1a8ccd3c6eae2 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 4ccd71bbc72a2164db5378f54e2a193d3d9269a4..9eb86309c70bf78a4279df5b5d62585552fae4b2 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 446b07d8fbfc59362426ec0713f1d868ffa33cdf..63b130cb1ffb016ce1688e7bf50541bca0e2d7d4 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 807a3263d84971167e67dd609c616e14663e5a4f..62a622159006683dfeeb7f2e021765808a3b397c 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 eba872ce4a7cb2bac51fb345735551cc49d82c6c..d3332da356372f9c666c5e3fd50609beb2fc5a0c 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 02b43f559e83405501122c2f1838486eda1d4f9d..1f64e2e7efd9628a3f2118eb65d92fc7cdc117e3 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 890d0a3a790bb010091ef87a766928e4543bedd4..8e14a5f2e97000ee873ba8778ec7d3c363228cdb 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 344b4c6a6c6e66f5a4dd61f031910b33ed09d413..ebe906872272bbbd2d94591a11717044969288e1 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 6e319bcc2326107962f020bf7e9d2f0028692298..7f35c196bb3e866500282d9aadb56ee7c48796ff 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 b724581c605ca519a6a934957cca4be9bbf3f943..48569cda847113743045ec9134659c0d2a3c981e 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 c97f20fca5fd315701da90b1b4bb8d7b8269c47a..39f498c099063df9877835dd879ac6c52991a46f 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 3f989f5cb021ecbcc89843fd348f7085292e82a6..b8640ad41bef26bec4e0df5977d06b75d733f487 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 0af1ef82a1a81a2b5f509a7393c0583f32e516f3..6c66fc335d2f7f2de4856cdba3a34fc01d5d9680 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 bf12849defdb74a5840ebfd8dd512bcd9cbeed9a..b21f5afe610fb430c880e4ff458bd75f070f48cc 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 696a0f6fc1da8ff0a9dd5cd0d4f3da6a7f4b84f1..fdf1b0f09f57e693dd669184be04bc9d9499e8c9 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 c05dc149048612850952565c21ed59edc799af25..b3b116da1bb0dd3521fa2a619133e776079d6d2e 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 49fe52d35f30eebf34af2498c924e9f739157fec..24866a5958aee5121c0eda3d21d15d96c1b5bf05 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 0c121b28ec3fe6ff2b2e193b01fb7b63b198eaca..3e47cdc1411d507f7c5febaa8be74286241cd003 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 c41a6761cf9d4352a37366edc4099ea8e19d6aeb..3366ed561cceefdb87a4d5cbf30648ed62ffbb5f 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 1292ec8d268fc41f2a9285051243a862647131a6..bc9caf812fc1b3a3c9d33c851eafee5ebdcc5fa0 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 bbace1478613f93c815f813e4ac0a27710727c29..258f82fb31c0ec104e5aa7a2bcf2c4e2f7f4db9a 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 1ff4969d8381fff413a32301c45e0e4a9fe8daf7..34481b6c432807086c262c9ea9ed94dfcbbab6b7 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 f16dfbad3f17988c2792d9948fc9236281d4e065..95f9aae3bfba777b8c6b7bd4956deecfe2b2cb6c 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 68bcb8980b1675d3ebcb17d54096dd13e4b09aae..7df010f757b197f063a29bd9ad6c45f5aedc9b07 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 38cce690db7044438a25dee2f6004e0b7b85a41d..61db7c7a35ec9cb4c7efdab5f54af3585e33f773 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 090024355eba4307b1bbf5c15c3c53ea5746ce44..697c77a4ea95938aeffd48e1c024bc709a5c182d 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 2d76b548b9421378d9d0196e5f259be5c5739c4a..25e27b6bee89366fa56505df9c326b883d0075ec 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 9ed4ead2dafb3ead2ae486c085940bee651db31a..14fe4032a52da774abbf22a0c303b0087d62f4ea 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 91a837b02a3661224c72cbf935477fbb0836ca46..2dfb8d9cfda126e4c66eef4c2dfc77de22f3ea69 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 dd87085d48cb87985cb476940bacad7e33d270fe..c10b756476b142e6487d3b9a3449f70ff29fad4f 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 e1276d143117e62ea871e08d3e14cbba73d44980..afabd95105d5bef795b731d0bbdc674b9f72411f 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 fac7b4699121efde7a59a5fc462bd62f59878f16..5dfd991ffdaab6e9737a3e54f5e809cb94700673 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 c97d2ba7677c91e9f613ccfce22efc6fa0ebcc64..2824be4eb887d5bb07fdc05730ceca536374d6fb 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 7db5819eea7e6e0df34d92605309638e01ee87cd..835148fc0f28fbcbfd4afc800d97f003ec303ea1 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 2317ccf633217705e7f85ed5fe0f9aa4185fd899..b453aed1bbeb443c669250af767ab056f64dd378 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 de5e7012ca03f440f169f356a1eb665b5688c1e0..ec0d34c339031c4d0c8a2b0e3342093533dc1be0 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 320544f69e57b37e8a413caf6b56ccd711bc2f6f..2ccb99d64df8372ccb4a12a8df18c5bf548d2650 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 5906a856be386ffc38d42f440ecce47ef083d189..a67d0d9ae8cd29fca810d9bc2fe51d392b5afc82 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 bbcb043c34a207618b130a17687a6e299dd58998..ead4e10097d00e0928c701a57094f82b325da44d 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 abcfbad94f00ef5e241156a66a8fba145ce0aaad..186ef98e7b2b88bb88b0c70eb6e5ed3b6dd5be28 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 9b5a71624fd0d361fa1b79666b1a5616c40520aa..105309774079807ac6520a42cdd559914e001d11 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 762151f17a883fdf9cd1d7e441d4a0adf97a60ff..e72ab1eb23983289961c6c913c7d56c1e02d39d0 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 930c43758c9230bc1d69e8ac1fb6ebb0f9baa9b7..26096c6b967e2f7ff8ac307c30c371adbe2ac35b 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 4b7837e38fb5f7dcb19d4d0ce5cd731470e91fce..0dc2cf0d05b1ec83c8907cb25ed0a7c85f21d55a 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 0b56ad5c9c1c08315a8c369544c2630060d6717a..39ab6480a941e9827b67e12662735271637712b2 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 610124c3d192bddc7ac6faef98b0398b81f06e64..7299a371827f1892d8b2be7c6eb8d1b6e50df712 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 2826f7136f6519c994f81095f50a473afee94e26..970679d0b6f66c4d6040cf1df60c9549dc805083 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 1b2f1dcfcd5cc54a624dea7697a7aaf3f63ba887..fd0af05cc14c8941100373f85df9103f4a8dd6f4 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 4c2a27f6a6d09c5886e5e9dbe9b747f6204b61cd..8ec1cc2889f2e3d34c5215bb06e81b995832f9d3 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 d30a6650b0b5591c6a691d303da86af2aa7ef4f0..609598bbb6c3218d6c25899fdd20e3302322fdc5 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 c9c240fbe7c63c083356f00eb56982923388ae87..2c44c7f3322a395f3dc9ecd4c116402059c39937 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 d8890bafb55d2a3f01ad4e96b991cf382d2678b7..9035b17e8c869ab08aa97b31298b86236da14277 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 8e9451720e73f59746642e6636d533b8ded46cef..006a8ff640573fa56e42a9c421cfd8f6664f5cd4 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 fe0b7614ae1b408647cc6d93e34cdfb0dcdc5f8f..3edb237bf8ed0469169cfd511f6728ad92a26221 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 8392a1ec33a7faec1a1fe0b013cfebacf8f8b8ba..2aaefed87eb43f8c7582ce595a3b2500830e1895 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 fd29cbfd3d5d2f9bb44711bd5e613f521bfb6b34..89007b0bc743198e0f322725164041c00180cc36 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 063e7fb4ea17df0ea35574e919e56f6040915831..bc817164596ed73f3ed0c4c8800214872061fea3 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 05e1e2be1c910e0d560b653c1d772a2bb639c279..3724bf4b77c61302556075542571ed9a5e67df70 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 f163476d080d25978bce23feeb848a6e98ebeff2..8d65a1e2f1a35929388d027be8f3ec860928d980 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 7fb58b48796371cf59d497ef66cf7b094353c52b..ced1f9f3dceed27ab49e044abe113fb3e1c1ad4e 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 b7e5cee2aa26888cef0b420ee4c3a0d960e726c0..6053d0158b3ba42033f61e44a0f9e46c656a26fb 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 e03304fe25bb5785f71cf873fc4cb734052d9d0f..6cca72782af6a004c02734f2d7d9b21c34770167 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 245f33c2f71e5cc202d0edc7187ace888a3ec515..32fc51341d99859172c035535e774f672c8a1149 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 e1fe02477ea8fca951232dabe7f89754c8f287ff..8d4971645cf1ad72a4f2fde8cb21b023b3dbdced 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 c09039eea707eddde5b3d742d4870231125e0265..fc53e1e221f0a021a28f0ee2a2f50319a7433af9 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 5869d2fede35f6e2753fe2ff6965005d9ced3569..6943508d0f1db7c6fc0359a0fde3899532da8ec8 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 93bb09da7fdc4e6a2372a0d871826252498019fe..5ae64af9ccea3d3effe15c3e772cede643b961a5 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 56007a3e7f110358e27ad74563f24e428cbae473..cbb770824226f664f9daf80afa843af1769586fc 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 b14bf1b2c69114fd7e9ac1e5159b74303bd03e6a..8f75df06e893cd1b09ceb31e44cbb5442401547b 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 de6b96036aa40fb104e84c6c9e58ba89beebb232..91c9f9586e0f645f87fe9899fb7f3e437ee85bb8 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 8e26001dc11c0df421c68e1ad323752e33af4922..9a5f3add325fcb7bb85370562846a1c5ce9dfae7 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 6c90aa725f2376710a31c98d19bb82749f14ad67..e71992a3c55f686c262b04e389e3bbfdf1a6a72e 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 4ebf6d4fc66cbed6d7493892620e3a78a55040cb..c522e9313c502d66c9820bcf812c74430bf7a8cb 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 8d9f36625ba5eb2efed79a4e2d8485a16db4ce29..8f080d3fd380542434e1d54ec22227bf28c7a836 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 e1f2d0eed544c0b318e9a59add5a329f2dbb52d5..22c55816100be456528ac25027d13c916643b0da 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 9985b7484a6b75c9a6c2907512d100d8b7cea861..c421899be20f27e8614e8c3724e296b07aefa227 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 6bca1d5455d4f6ce1997d39d09792a90e65511a0..9f26d4310bb3465132132c8a15d7bfe54c1dc7c6 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 b9fc502c58c24a146c9e5c5109312a2d40c7d268..a76b8a8bcbbb6c27e18bcb69d8ee6bdcbe668d4b 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 2c9fb1423a395675b773b86038e39c1ae3ab7e04..0604b49a4d329b3b9a0592afb8275d3c4d33f0fc 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 33eddb02ee300238897f0f9018119717b387fd58..b018b61bd168edc580d24326f6c5d214dea4fa37 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 f31b6b780eaffa6513d097e6e84166e5f3c5a684..75f66f8ad3ead620f519b8daf134259f3aa9f172 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 8826111fdf4ae0d75d4451418820f304df8dad65..aeda5390106415fe81516316b4fa8216207affb6 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 fe0535affc148fcf932c12fb1bb4e4e2f1829826..536426f25e866dab327bf8764e4b19a3422d0590 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 efca509b92b05eb8d1f1bb486a52c1ea27c0894b..5935fd6d1a0581178c6e4676d25c740415899cb0 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 926311c792d5289b8c587cca180dc0462e0caf40..a242a62caaa16eb84439c5a31c82be99ca73d95d 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 88c649b3ef6141d0ea07dbc13c1174a3338cac77..eb466c2e1839eee0e1e5732e92075ee2b21953c5 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 ba0b411d03e2e1fa8df22648ed466e0197e34e13..00fde2243e486cbd35f371780767c4d68eba1384 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 730b35e7c1badade3a722eb19159e1ea84913b4b..604a5331f639b16752585cff9908e5256f36a6e9 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 901a31632493c1c83d95216e65c14ac14e457f48..3b84db8d13a9dbba8d538a94e81e6b687abaf0a7 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 76e65a32f38cef5fac802cd68e76c7c1c2c63e49..754f2e82d955ed92927776e186e06200218d8ffb 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 a75e74ad1698d758ccad5c0cc584e45aeadbfd53..7796799bf04a376aff8f46e82c1278b7fdf5ebf7 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 8def63c0755fec94a694b8035f8a22de163a697c..9e50e5b5376319932e40db482c578ce0d4236f2f 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 d735e87e416ad8f6935d250ad5c052d60569ae0e..50384b4a817c8fa75b0644a3ff6045efddc43d48 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 66d6e1f4b3c3cbf14de72942d039c0d1391ddcdb..da50e87921bcd6c47aec83c6f45073806fc979c6 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 76e7ca864d6acc11f1b9e72b06e7585e60645a16..bb88995a12c738ce4dbed487f9761a57ce756bde 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 aa87a6b72dccdd4d26f28e827716dc5b84af2f9c..91b32f2a1a1b62148c8edfeb3865ebcecdadd92b 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 8d9a8fb2dd32e043627aad442465ca14dc95fa1b..42a02cc47a60b88245007e6623594a037a81b4cc 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 5879771d82b2653ca0a897932217abc8bc8759a7..cb746cfc2fa89d37d3f6fb8e8bc1a2a2d3a7407d 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 d99086ef624405de15af9334c5d98557c2d85936..e9b15d45f98f952b3540dd1a292e8e432d02a734 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 0efd55baacd3352555a266b6015c6c5bd6ca3fdb..5f0f6df11adfa60152a4724d6ef8256e27a77fff 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 ffd7e9506570e0c77d32b5a068062b9baebca4b6..43a6b535077546f1d1bbabb77a15abcb7d6a8cbc 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 59e023696fffe96d3fb7869de5233161dce8fa1d..f8c88fc7b80a050039b44e5690cbf91805b040c0 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 f6afca4b231915cd93121ea77f906f2e14c91d02..7825cbfea4dc49f00859a9018cdc6e805f0409f9 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 4aea97ee4b24c06c6e01f7cd11d9e92077035396..7f66a778320994908bbc101e344b9840895c5e35 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 6ebd1410488dabdd27e198252810a2d069b91b88..e60916ef7a496df88e8f89a7d2c3265b5254c9d1 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 9751309f8b8c0d8abb3f8458d4357b43ba61669c..2519fb7aee51299fbea2a15086e20e74c878be25 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 d06bc1a817a191613c5ce037eb52ae649a6ee925..079c04bc448af9a15383526fca7a3e55d40c2a46 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 9d29edb9f590ed145db6f2f533b9d7cf0d01b129..49aa4e657c44fc65f01b59c88b539f47256e8f37 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 47a013fffae73c1d416b68fc6b81dc5274bf2c46..3ad681c4c20ab7d76e00af995c354644d0a3bbc8 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 1b18cf55167e0a2e2c8a7a7ff41de1a6c70a5ec3..343d24c7e788b8926c60318d4ad160f9ec5aba56 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 fb6eba331ac6eb9f51496682da04f50a33bdd063..26fa1a4d1e6bf12665fba5cdf405ab7dac461372 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 719e57685dd5662d1d7d4d46e35b95a76accd078..6ef93c7af954816b1c87189fb5d7fc5199c83c5a 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 726ada9b8c799f804f5a506232a49604937e5502..abcad097ff2f4985413eac39209183751b1e8b14 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 b1e0f7d2b396398f894fa20e76416a8eeb3c79f0..a1852f6c042b9c9400cb61501653a060ad28cbf8 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 9f7e2457360e2dbd750542035e8e8fccee98f15d..9fdb9c9fbda48295c0abd6be1c2a8f476b4869cd 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 d50810da53a9f82edefd333e27f0dbdddc70bf05..21c43b18d5d5b6bc93ad2298262631c0e78e4193 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 1f1e07e984777b13a4e7059bdd83edd73e1253b8..01f1738ce6dfff2f4dd8f356fb3aa2f9dff90aeb 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 b71f5ac6c7dcf5b1b684061298c397faf8c61553..4ca4b1f30bd08611a5ec7e83695be8094bd568bc 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 38a10478605cb0662f2a724061236fd95cef90e4..7c86fd248129a1b6d213ab5f7c0f056d639c08c3 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 ede0674d83990e294d21855634f664ebc2659f20..4f339f939a5133245dd6f64fd2831efcfb29f5e3 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 2bd1e014103b0b3c5458aa132a482191d5368323..ea62322ffe2bb7e711bc87d521903573550be282 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 b0202bc0aa62da222223f3bcc21d3db58815c303..b7216d694bff1598dfa955b238a0a8241a524b82 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 866374801140fe6e8e206258bcddf67933e03bae..68e9f96242d37ed0aee8eee0613bcb1e456cdcab 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 4812bbbf43ccbbd3a9e0f9d94e54b58838cb5a45..ec72c39997d21a004478603220d088da0c00a31b 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 968ed0fd37f7f313db5e2ee2e9ff67a27a63e645..f12780f4cfbb1183854b8d25b7a1da32f40653c6 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 eaaef682de251b893b1877ca94ebf90fb404325a..faf43b1d3dbef626610744daf4d3ecf6220489db 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 fdd16d9f55a14619384beb4f16a218e131aff90b..946642cee3df768799fd8c4c0724d86709a17f15 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 06170824a69b2cd17819e2d77e477f414ff89944..faa596f9e86191fe4512397763f5559d393d78ff 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 2f3f603d94c485c6db784b2abda10274f7b39d2f..8ff67deac10ae9669ad2750ddd7347e9b5a3c0d6 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 ba996fbde89b2fbbb4d029e3b877cb3fcdbaa99b..f9df800e706723b879fcfc3c54b4b3b09cbc18a6 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 4329cc44bb55ccf86f8dd5854dc7f1cad2b61dbd..f9e6a135d6565416ce548f9f573cd2396c7dea2e 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 8e4fd1a98023ceec0ce482385cba96b013128c17..3aeca387b22a4d3a253403e269652bb3bf108c94 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 220a932fe943fd5e9a0d9b4e3cedcd4958c1b66c..f7e93aaf1e00029c422466294dba9a1e45136ee3 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 dba9517d95537b15bde23313a2a159a3935de8e5..9c5566217ef6a31669bb1469e50d02dbe2861563 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 e630e41dc8430a66e691796ed3086e5d87f08721..2adc2afd9f91c96ab933f2bde5716bff05c363de 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 6e74d21227a52b6ace1c90de6a42c6eb09e64894..12177e4cae6530c91a7751b6ad6fc3cdbc63c0ce 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 fe9a785b7b6f39f7e59a8d1674226b7b53f40c54..ca724fe91b8d4df15a24ab681631db11082598a0 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 3dd1df472dc6cd46a8997e56a038d8208d0043a8..80ab9700f1debf4f59984486dc6ef3e336e2848a 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 12637606c46de0bdc01d3a130d7b0a496435603b..50b8c1b1276717dc7d8b8206e5deb7c41bdc2aa8 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 4dfa0685a86c79f7717f3aec75568d0f553b79c0..a32b3f0fcd155c789c8b428c8a965399a5c4fd1f 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 7fa73eaca1a8538aae1bac904498e2d864cb4219..c013c80fe4e6d3fa321ea708657794f08025888d 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 a2f4a55c51be067ac7e79154b9fa6aefdd98f8d6..167d79d145ca52fc43ca68db44d87c228e30d073 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 8aacbd1e7db2c28b601e7fbe796774601dd84d89..684662888792f6ff0619fcc3c8a6c99a0909e42b 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 480219f0efc5a679f02429a966246f4d4bda9abd..6afbdb044310555c26a535069254d294969afea7 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 fb0a17252f868abe6a53dd88024bdbdcf112c257..14a1a2793dd5db3049cc44a494f75584637e31ab 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 b2bb47c14d35a322c3d8531fb19d336b72c4ee32..d4ecfbbe738c730676d0ca3beddd41aeb3c50bef 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 1ccfbc7eebe0323ce88b1c450e52bb87aba3c45e..27c731a3fb4905fc3ba16cf01267cdc8c6b18190 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 60ae2d0feb2be84b27a1d17bd730dabe94cfd925..5324662751bf11f262a179616e7eea5decb0fc8f 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 6dcae0e50018c173bf22e88fedfd9e916bc59152..3e0b8ebe257ff93ba5c87f8bfba2ef289fd4fe74 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 b7d7ec435487d570469dac8306fabb909560d6c7..519edc796691a627518977164dda1d20e15a464c 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 1fb6f6ca627e85e2355e56e09c299d1c02945e81..8906aceda4c43ddd950394be27fe92afd3721e30 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 c544f48a1d18edfa916c34020509f1fce3251fd1..2368f34efba3807f1c28bdb541ba8505f045b36e 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 a5a24dd44e7e15a2ba7f98881d0ef2fc74f7ce67..02f5b44a268577c15068af029d00cdddc2f15350 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 a81748e6e8fb1d33292c3136141e09b671ff0f01..97416e1dcc5b261ffbcad3abdb263286fc684dd9 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 d193961ea82f1c308ac14b679f2a221727c7ae92..6b85016b4db360e5eadce1ac53d3524948db31d2 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 109effd3557d38f7f3d7f8a183b40062dd2a4e98..68a8217032d0fb17cc6be74c18490d2b34520f27 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 88eef3b18e4172074d23b8a75a620986af128128..dd38c356a1a4b0e405bb15aa9cfa56bec31512d8 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 ac6d8e3f22de9ec58000cadcb9f4a429c9cde529..ff17c6aff63dc6ef75db460769a2e1fe06ae5b86 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 301de40eb708bd58247289fa1be81d801d50140b..1128d86d241a6a8d170ccfc5911b890deea6726f 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 ca22526aff7f6f0d6b3a35adce27af12c79aaaf7..71ff3936da4f945f3d8a798a8b2129ca3c07ec22 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 35213082e933bbeb3510a48efab2da7616185fa7..a406cc825426ca6f5b1de0b48028d5ae2c4ebc00 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 1a4095c56eeecff77f575088a07878ab96d97f5d..bad2b12604f1b49ed60c40cf1c146a340cc4149d 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 bbe69ab5cf3f3ff450c0e314e68facbb15757c64..f9669fdf77987d74159ae7e25a3e61bc586ca84f 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 54772d4c377f9cb7cfc366621d78b59e311ac729..4059655639d909e8799fe991a6f4d0961820215c 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 22e3fba28e5187816fee62b1017e24ec34172a94..963094b3c30078f4761169a657928ccbeeb8285a 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 d3b8a64401131a67c567626eb1c24c3fb4415b88..67bb4a2a374232d18c2d7e2adb4ccbaf47ddac2d 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 d056f5e7cf9306381631aaf1088b41ecf4bbc972..2e58cff9d2005b0cab783ab22653cb27e8333ecd 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 2fd5c09b42d46af984ee30688cb676afcb6c5c24..1c1f63be6eed8b31fa043f9b81d3860d832943f0 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 653d5ea6c5d973bec1861b7a55c3844d82c25ed5..1f5b5c8a7f726d8d1f9bd758822f73d578a68197 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 951b043e82d07c5565f4e2124f3adfb20d750c4e..d125d1bd41842bf354d25c558a18ba0593932180 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 struct request;
 struct seq_file;
 
index bfa569facd5b92f79688930d02f33a0e7cebd583..1c470e31ae815feb34ffad7b71a675aa4ce212f3 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 65d0a10c76ad1a71c1476fc1103dea5b73f64bc0..e1da8c70a266df24d1ae89181328007f33f4d711 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 48ee68059fe60831c94d0786ccab714c628f1660..74ded5f3c23675ba7c3be2b312601aa11c48be0c 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 5f21547b2ad26bce1e5385e5720279ae8ff8a563..cc2859d76d811dae9817930a046ad31c5e2e66d2 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 7f0ceb65c3f39dcc89ac21a10f36de6391b5bcee..c074631086a4db3e38c03d6a1425607472afd69c 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 dbb206c90ecf3c22e68ea8746ecb845ba78a29b1..64c96c7828ee1056042da4a913d9f3f2b9506506 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 118a687709edc99cbb6255d75e53fc632b0ab845..2732fa65119c485891c5a25666cc768b21b6ea04 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 a3406bd62391c6d7406f79643889bf361881c8ec..149d406aacc9e672b70c100289abdce66e18070e 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 60f01a7b728c52f418561821982ab5676f71a1b1..c2afba2a5414df7115ed16a289b33fde9002487a 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 baada5b50bb1194d6905c90598a587f4931d8bc9..e3266a64a4770a940a93f2a0b66dfbb446db81cd 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 b89269120a2dd3028bee98d06e617d5666c6dee5..c2b6a0ca693335b8c7a2cc38356073ead148917d 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 b4d1b5c229873b7cce08811e49b6f75ef2a4f985..ee4b1da1e2238a959a3084228319bdc2f3299a77 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 8d9332bb7d0c30b0f9e69aced0548f5c728407d3..f478685122ffb2be85f3dbee1c7ef29c8acfd100 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 869e71f861d67e6d2fd43413c7e60317ddae7703..a9344eb4e047f1e73c28212024c1e8dcefb19228 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 ffe6f82182ba85acfed705a2b97c6aa8526276dc..3b19de3ae9a3014f584acdf22023b9acdd03b1c9 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 3fe3029617a8b009f4704ba94b3b85d1a62006a6..04d3686511c87ce7886e4338ba3f523a4d877077 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 ecfa898b9ccc060de3cad2bd08084b2554a39a9f..994d73d03207ef51a68614a1eab1533411aae824 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 6fa889de5ee5eb83341b7bb5e12e2d04c40dbc56..dbb75cd28dc8a23787be8223e8be8134855c971a 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 13f1b3b9923a8becb47b3dc59a77a8f5780816fb..1705398b026ab5154adf35de5bdf213c8ac5e6e1 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 377b07b2feebc261c08920f309261e8302217b03..70008816c91f283200431e2ed8c4f17389527e5c 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 f965a3ee9ce58b90f5d633797b3d1084d8d62a0e..fb7b289fa09f78e073402e472d2fa45f9d95fa14 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 c2f40068f235271cc694b56a7f9020dd5f8f8a2a..edc8a139a60d713857333e7a16dae0a258b6d553 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 b2f07d2043eb3f56dec182f6494740e1b33766de..526e3215d8fe18bb7a29ee4a61b86000c8a8ec56 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 ad3e2e23f56e67c359848e80098dd85b64908ea3..a444badd8df5a946a3fe51a3347e120245f564e5 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 2fa05324ed074f725ef93791144af2db3a1e0eb3..75f87b3d8b9538a2f5293deb4270aae350d04721 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 6b8ef01472e98af95df2053ab60160a5ac2391b0..d5cf953b4337020acad2ee5fd83973640f50fe13 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 aac35fc3cf22c46f65deb7cdbdd7674d72efc394..fe745830a261a7c975dc524f3d6a0c5a0a9e7062 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 682789bb8ab30bcd40df538817c01f4bae056a56..ff4badc9b3dec599e269cda5f1c39b9ef282b305 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 60293a00a14ee8accbc5a89d213fdb35449e0eee..317873bc0555deafbf4b2e26a44a1e67a59cfe9c 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 71050e5f643d0f4bc4078d0e2bc8622ab98a0543..d923b626233026aa691ba19b3caf29c66b0939cd 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 d3d6b54c57914c52c13f0dcb8205358c927c9e92..70637a0383d2a1e75f06e82ec4d68ff32ee168b4 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 c1f51d6a23d22ba404e6ce83b0d424cd2682b9d4..79fee1b21ab6e62a8a4a47dd21ba0041a4379508 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 1d5294b8783b710a45366488937926b8ab39d08c..a0476755a4598066512201da2cba4d76981e8b89 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 91673351bcf396bc69a8026a5ed6496bd2422d7f..75ac046cae5267b712fef17dec0ba1f2d381838d 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 178df581a8fc74593589655607dc7aa9ec36cebc..989fe84a9f9d79bf335d294118819e74a8cd92ca 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 17f3a7569e3de8c2e3d4301506e2f89ce8a733b8..5f4487b1a22440249cddd88fe1295ea2da00afbd 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 d2c8cc72a99dd9d42df5fca44258b8178110c815..3ef3ddabf139444d8b49259c62d2fd45c19a46e8 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 f6d1287c7b835421705488219c88c8182e6e4828..08d1bbbebf2d7b59edc87b8dac466421a171b29f 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 8697dc02ffb459511d0256ba7a8c1072bd03e271..0b2f04b02ebc2e78f75d0023c284b2dbc6a04532 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 65f60c2b702a6cd6adeec6c3e80f1ea2c15e0a55..f7e673121864bdeb5867629b9b49014fe784f458 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 3be927f1d3a92694faf94dc664f3c8bb829ba804..e15e33ed94ae3c81566895633b499a8dfc4a8067 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 639ec15869760f5406df8be4f4a6f4f3964dd407..cc9fc263573e11b394a5880eb0b2afafc6a62ea4 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 b8f54b7fb34a775fd5e589d7dcf7d68fe8765ea5..0350f303d5575e4c384ff7f4496afd1ef9339ad4 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 38ab344a285efbf7136074df42258c66df9ade70..e704d9e51514c0ea4e1a2eb93534d0e4a01b9348 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 746685f90564e25f94abd165ce34631c259f9f82..cc31c3e5984c90081c428439e6ce7bc76bc1acfd 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 9bbc68729c11052018c26335d6b88498e3491b32..dbf6a151886c437c80fd1365628272c4fe32c8b6 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 8ddb2b3e7d394513ca3acac4a2953390d576a5de..9f61abb7c1cac7b18da7a4e72c74ebc925b2a340 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 c7d3b815a798320292f23d718520beedb68c8e3b..4c3d8bf8d24985d3d5906eab683141102d3f5cc1 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 382258fc124da1afabd1ba5bd9088a91a0bda216..963cc1b8b8961b0f208a642f91f0f4d9a6f58e65 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 d8d9dc9dab437866d9284ff7b405565bf1c6f9cd..fd3ae78d0ba59cec223fc46edeabfcc6a20f1f58 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 cadbcc11702aa7a0eb5f914478e9eed5ad5e9351..54494412eba4189fa64844d5a4ef207e5ac74e51 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 f37d8fd147717709ff59692629513113bf0bec59..7af0ba8d84954172d0d8f5e57e96ab171076b304 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 9ecaa872bae8de7af47cc7ad0bede41048adabcc..f0dab81ff8167f89d1bd21241abbed335dd810cd 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 517e5ce8c5e98d3b723ab7762f48980fdf69570a..ab509d75aefd4e5bb65d6bceb5a9c8335fb46e59 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 3e7d30b6de1d20fa8abaf9120a2547b35f54e007..4bbd3bf34acd9d52f8d58fab595a0ea9e77e0352 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 8bc3d9a877432e30663a869bd90b3bba479bf37f..635a0a7b7dd29b66a010a7d767ea946b6ac865ab 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 a167fb68e3550ae2035b85aba10731e386e7aae8..2ecffa42e561c22c880d832cade2974b5f9d58ca 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 60b85140675ac1d754ec483ae0fe3431c9bae55d..f6f5b92ba9143700e16dbb0056acc021151d9587 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 368837cdf281de8c17f93ce6e7c65bf5cbdb8b81..244237bb068a7a77d037c7cea079e0f2c69ba953 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 e3c3e427309ab020f082152085a280062d991a04..f73edaf6ce875fedd0197165795c5b3cdf56cb27 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 a445d58fb39998b6f7ee067b91645233bdaa1fda..13179f063a61d8d49245fce10a5e896401db99df 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 0ca48e688818f345a3e23753f77300ec5a2a8b8a..7ecfba4f2b06bed565df50a128be53ddc1b9d790 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 d35c4fb19e280ed78b847ea3c150b1d026eed313..f6d715787da87e4b0a509f2483e7264ed6aa01fb 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 2fa88092514d19646ed0e8e80e4444088d89b42a..cebc1d90a1800b1b4a566beefbfc2e29ae5fb74f 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 70381756a64a804840616e0fd7da720441181ea9..39687139a7d3fc52c4dc9c4da856292c074b4fc3 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 b80e0d248b0f1108b57d6e093b2a455c587cbf18..62f4b3b1b4572661b38d8459fb050bd1871a4b35 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 23d9a655a52015df8a4eaab71fb284a554c85a6c..31cd9a12f40fb19ac3964781c720d9a7b7212c0a 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 2066241b15b1a81c98e9b3f47869a641e317dad4..af513e003da705581b1e348ecf557c927cfc73f7 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 dc8c25ddb97e7c6b70d064bdb3517c82e9718b38..9cb3d0e42c38cae6e399adb77d104523e381fa77 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 e075244c602ba277dd6441fd956b5d1feb31137a..f4954d85553efa3eb7911408ac400f3b05c51088 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 47610d863908b87fdf5662006f8f87ba68c9ada4..21527d84f9408cb737a6157e14d5c09c89f0731a 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 6de3cd7363d7f71ccbc80b9cb679dbda38bf71a2..038d6732c3fdbb15ee98c29e04cfef8c7a2091aa 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 b6be0bc202f504cbbbdb18bcaaf77622de6d3c80..0c1bd108c38645cc8733549b84b6d3e94b7c513d 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 3bb2efd511c4852c95b9ae07f1a705665545ab23..897965359fcbbaf8bef400fede20995791ebf472 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 1e48e9df132942253c52d8be3b2c6d65c7ab9005..d15ed49807d500dc9df1ed11a846b6ad12f082b6 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 8c7af29fefae595a61744d1e4c9129e0b518fc56..9b5ab37fb3a0f4d90488c4c2d4f6b2a4c875b49d 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 28ab1e185f9fd1ae54af5e8b9e79eaf77c452de1..c274ad083db6321ae399ae6e301f367c36b33ff8 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 e0dba91e7fa8357acc99a184ca5f7b96919349ce..c124a836db27e04c157286a68bc35497131619d8 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 40390cdd3c8d6691b07e17b321aa7dd319a0a655..cb05cca687e1bb7736f9c70d5d0c39eb67b4a6d3 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 f35e636b1fb76d5edeb4d5f328c31da5edb7b46e..21450e3d408f09bf7de6842a383c58c84383ca5e 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 893aebfd1449179b915caa3c378ce1819a2de722..cb815c30faa41f84c10ef2e6582cf7716b3be62c 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 ef8008bcd33d22378ca8b1866c006f7ed6a29343..16f37f002dc625d7205164593c9f9eabc30e52d3 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 6959bac11388a1b0b1caf32c77074608831af5e0..51a4dd534a0dc2839fae52dc75b6c32d2ad77ed3 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 616658709bd9aad6e4ceb9fabea66941c9787821..48ca88bc6b0b4166accbc7ab0771d008593175e8 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 aeae58d9bc18ec09f05c4e9166116cf277195ddd..a05ae6d40db9d27bf731c4660936ffba5b98488e 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 ef913b7496e6d0d570fa6399f19f8fd62d64b582..4c8cc866b826973ad02d7401ed6147d57455b7b5 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 74551eb717fc7b6efb11756df57c559c0ccfa5b6..4b379542ecd500b5d2f41a5f9a583b45f0a6163f 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 e089366ed02a08fc8b44dda64247d80c91cb33ab..2666f9e30c155006a5d68b749dbe7d53c7b69997 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 25b3e18c4d9121813ed4666033359e0bffc16c88..2bf811449b0b0dd02199d451989ddb63cfa906dd 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 56d79195bb3c2c51deda21622dbc4816b7da1030..2fa8dea1da4d2a83e1302f292a0ddf073d2e220d 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 db32ea7d1743639f8f98cada873ed28b13d69abe..8948d52464091b0925a3ce41fef719e09a6c5d8a 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 1d8bf29e0ffb49218950b976acdc71d42dee8b7c..025495657b68a805b1a333446f8b6d6ba78bdae6 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 86a8545c8d9740734ec3f15f89b2a66148792481..b9841adb7181bf28155f2950c891b7366e0256a8 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 c8a64e20902736e2c9b78d6cd8132f9308432ece..aababdf2be12c8d803171b917bc5e76a9d8fb5a2 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 adca250062e1beb29d8ad48bce0a038b2b58994a..6f6e98ab0550073132edd745d1313552c844c309 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 0fbb9932d6bbd3c9516d6d89ed00704dce24fd7c..60db06768c8ab9c4bcc78ffb53deb7a406d64557 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 3ea08ab9d0d3f14e1da8f0ed6801b744c5088d16..6932ab7acadf3f518b398c5abaeda3bf2301a392 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 aeec48a4edc7c25f39258578e2f1848a24f286b5..b4ab99fed932b1f3c7a3975f49b2b6d3e4f2b3aa 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 15803132c1ea798a28b2e39bb4f848d9f2d113d2..1b758e5c84e00d486d0a8ab213764e0d82fac47f 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 250c15ace2a71147be4e6f14e522b6a3e898745e..1fb560ff059c83ff3a130c3b50bd20c0c67620d2 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 280ec33c854049a16646255eb5aeb810aa84e2d1..a4c08110094b3b1345d2323f58d90a38bb99a820 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 2576f179e30afe274c78d1ea458a7f1145ae1f99..d2a07f145143af1a2abe96cedc4fd0754122885f 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 5a6ee4103cd58f43f89943fa0f1922b1d39ad825..604ec813bd45f432b2a2959e11f819dfd11e73eb 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 03d919a945521345bd0270bc4ce3dbd702913864..89fa813142abe219a502b87203f0291c5ffddcac 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 07a06c532dee244aa2836d39c719e9307390ee45..05079f7be841a8d30c848c752b33e8e30735d806 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 aeec16314e0d75ed3b0c765249dc768a5d6ccd31..cd2b777073c42bfbd7cd63df3013426e0d32750c 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 c889f0bdf4244682e39e930eed8eadc1c603eef8..40c6f4e7632f951c363a6833030232b8cef20743 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 4cd16257f0aab57c496b74832cbecbcf537db395..7d86bb8be24535a99763b6bd50de1d3c7d67d5eb 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 f925a83c324701d3854a546d2083c29f683029d7..be5497cdace0b0c61782bd8718ab0c1fe17e6e32 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 de3e357b26404d2bd2f678e707664e4df2fd3856..5854551d0a52c617b058adf70ce672e5dc2bec97 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 4f7ef287a0f24362e7880967fc8782c1535aedd2..970d5abd6336389a15b646ddf13ffc594e4f2372 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 797ffa6e64d5a31893cf8d98f1f090d406c9a63e..28b3cdd10397f4cc03ac9b2d6c18a6e7e70c1b67 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 9a4aad5ec36555500023e3727e7878c8fa3deb84..d2f7a88e992e79c5b1f257e482d7ed060b86e6e6 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 8f28aefbe6f97047e043cc32c3b1e97434b84af6..6f3c03201f649633e6d43487fac633bc5aae63c9 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 087f6c9a58261c2a2363685a26026d392fce3577..9caf7041ad60e2e82c1a18b376126f9641b62e92 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 f404370d6631b104978796884fb8f71fa3fa8020..7bfc5b7c27574872cff6a4bb05d4826167bcf354 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 ff481fbd074cb7b5873f08c044a320ac3e674caa..95f1b1431373f9c711b88de92f1d573f15bbd078 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 74f7c9c81bf63ed686261f3f86be98bccdfb151c..4e2f6cb55a7529fcf8bcd1de5a64574a840c55c8 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 149b0009ad66cb0ed5bcb05865dee82a3311d91b..d5a9ac51e9071f0b5a4ea3ac11aee9c8609ebbfe 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 70c02c49b1770f20452f721ed22db48fb264c95f..ac555205075286ccfb326850805fe1d5f1876341 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 2f7bdade40a5996b58066af59740a27f05b4580b..93cbbe7ba1fd645a447999d07a9accf93d8b5d58 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 c60b833ca110a163f62043754be120bd94a227cf..d569fe5ed8e6b65d9e5c7f2ad7669a5ec7ada5b2 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 df096c37f5ebfa25b0e6da0ed41e5cc2d06267d7..5254d875f96bcaab9a13e9ce766b190389238c47 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 db25eb580c98d11266193356752c01cd0b6cd87f..10525493129bb3126b4981eedbf5a7948faa4397 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 bfef66525944ddc5b1ab06ca79821ce48e65d7ea..9abb7c32019210f35db722dc57f5c70507e6780b 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 1fb2349bd0a0ffebbf7c089a23d9d334f8498acf..327f7d1bc20ca5b1ebd9395c0c304d944cb59b6f 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 eaa4adb32a0de299ae5055d7b44929001cdcbdbb..ec5835d1aa8ce0be9bf3b22c45aa0b095993dd9f 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 9db11b16cb93a880acb1f604a94a160f54f3bc3f..e660bd4d91ef35994259a84edd1632eeb8ee1119 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 2c088af44c8ba8d98f146a848c81a59076d99461..8907bf6bb7ffec2b89e2e34a7cae676eab42634c 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 7a090615dcbce992d3679947830e673d9e479236..daf6db354982df4b15e11bb43a201e147544eeb7 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 5215a0b5fd454fbed47b79f35ddfdf4558194036..7d78f16efc1d2f677c563a976131e8303a0f3adb 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 55d857926bbaf51b3bce5daa26a18654f4adeee2..1b7e3fda7905f476bad29bd12cd5e9cb0ecf4651 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 bb13b1de27974f787ab43c415dcfa20846c7c1d0..64d9feee1f392d33fb575336289570e565caa300 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 d7975aa335b24c406142a69a19186b6e83410b1d..4a6c3f6744317a770a1bdfe61478c651bd9cb50a 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 0e762e5596753c59fac9cb922ef32e652d12581f..0a3e478fccd6e30728b4482e0a9455f28b415daf 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 944c8894f9ffb7734fcb315251054e7fe6ab7107..e0da0900a4f74fda48340755db75affeb21d3150 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 aab1586fe0dddfd08f32662838271614d0b859e5..4a8d16a45fc5d28788171f8ea2f30fc098c98980 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 8e1ec4409b4f92ecce1b5e7d5ea9ed963c4e40b3..fc6eb97801e1c0c63091d7666c54ec03b7c372cf 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 dead134f6de075c8fb80a392a35365cd30e2851a..be08cd1d37a79d2b608f3ea1cef2b584c37dc092 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 7cac668bfb0bca24b3c5a9e6489c21b82a893df5..59d179ae7ad2ae058f0f1e1fafe804598b4c4bed 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 4065a4710142f63bb149d6162ea11dd60397789e..fe1f279ca368b7370b2fc9f659113e78b9ad9037 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 2ba01041406bd33210a45d8c0654e149cd052ea7..ade14ef0573097e5a3041f11f1c63893ebd3c1ce 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 0de0332906bd3feb39164084ca08915a3fafc08b..0b2a1c688597caa55d400ee011ca0f692594a5e4 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 9ae86631fa8b87f3e72fc00d787c4e2681985b7d..0c4325073c638c7a9594c781cbeb3e3485051cdd 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 401f0e442bcf472643912dcb84dbb99e0661eb5e..40145c0338e458290891f9e36c35cf2622805a2c 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 4cca7390c8ef9a7afd940b0e976c906a45c5ac2a..b4a099169c7c8d1ac4cee68533aa2637cc5e649f 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 4d473f008aa48f7c3f5d2735402a5edc257dbf61..b9f5104f3bf75a0fc0f132886fdc418eb379757e 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 c962696c9822f5e143a78468ba4ddb8e0a6e8876..b554cf8bd679a430ba1932751a8e95a3b76b8a26 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 4e20cbafa9fbeb49bacc73ae0db68201731c6ecb..84c4c8580f9a3314cfa83880c7b535f23274127f 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 00babd011a62d4fa3492e67f956d4c6f52fb05ff..4f3b54a7c3beb5a89c7d5b9e7debcdeb01245ad5 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 7574a4b569a4ddb943c97db33548d59854150eb3..307b0e2929761fd932b428012c8034b179eeaaf1 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 05a78ac24987c6d74e5171c1c7fe57b8c032dd49..26b618008fcfe731e77bb2b0e8ced6eb4346991e 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 262984c58efb9c6aa19dcc5b9688c9dea763d8be..98d7fbfce1a57de3ab1ec1ac92d62e8006def74f 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 0027d8eb22fa720b133c427e9c493d08b8da13ba..221bf92e1b1c3f3a2f00faf4be9b24d6708c380b 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 17dafeffd6f4f136e4f710ebc931f58f9606e790..87024d6a465e675e1cbf518f97d451cfe6978087 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 a7230c0c7b23e3b19d1c7ed5cff194fc8fa2fd5f..b08b9a191a3416971e19f9d45e7fb7bbb5f32582 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 2dc20da21679c3250e6e1f1f46ff978ec2208ade..b78101afc93d3a86b8983718906a8a991858361a 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 2622d5e3bff9b2d5852369705002b097f9c8d7cb..f3c0a9348f56a367696197e3bdf936b2ea330d99 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 7c7267d0fc9e3da3dca053f9a5ecad75107994e4..0cc879a4d43fa19446a33fa428afe728e5a6ad06 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 8a54181f481693dae7f098de588f1deb4cb88ee0..a160107e98010ec351fa0319e539f49404d2f52f 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 ba379506da3fd1e6cbc7c312979d440348e947c7..edd3da05fc062fed5f83754677cc629221025d10 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 588346da1412fc02c284a0a6b8ca871890bb292b..aa8f8500cbb261feb5a11af4f474c64db2253a2c 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 44cd911f2aa139da58c190dafaf2d87a2bc7afbe..64e2ae436625b762dec8e6e2db166574da18bba0 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 28f736913292ed0f1c391aedefe2ed7e314260dc..5298fe603437de8b0c866cdee6e0cee1934fc595 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 f82645011d02038a7f6405b8b517a2a4e7e187f6..693008bba83ea5661f60e91a7e26105a9825c7af 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 7c30b9e68e702c82210a3ee922155b147d6f1f48..653812c5d5a83b300870c411f08c401ae6f59684 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 f6fe8ea129611f46811258464873bd29f8a7c5f9..0a26d71e5340267686178f6aeaa224ee897a34ba 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 3bea2e374f137a1fec88a98b6f887b1d62144f39..4199cb586fb1db6ff5a4c1cbb041e7de67d2d95d 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 45dbed10295f0ccb0a339bce2e003a6642808e85..d042d900f30c46c8ab62af06db8d9d12660754ad 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 02e73c2412d4f000257b0357a6406b43a16847a8..6cc4a704c3a014b29ec107e893eaa03b19af56fb 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 7478bbd3de78c6b6e47b6de852ee613520594b73..d0daae0b8299c56b09ee6a5513e8f463c24493d8 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 eef52d5c730a4ce7fc733b7e8b83a940e702195d..e64845e6adf3dbf2424595de689d63c22f00262f 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 77346debea0377d9a83a9810e5df9d2bb3ec1990..1a5b966a167ecc4fc5fef302dacb7476a1a594dd 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 8bcb0775411fbaed92730e7a2fbe5e927b1fba0d..01d713d027b0b695ae030d3ae3693994b6b965c1 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 744091d46f4c936514f2792a4b0ba9f8679f6377..a88467334dacc6b60527e82a1ba4bbc872ff32a4 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 58e02f944b6dc0db5efcacd5caa3823d876bcc28..45065fd3fd5d5a08e4b18835346e814c9db64531 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 bc023067245752be2065b81ee740d5de2a286530..7bd5c61b055c9e2528e99f6ad04629777abbe8cb 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 35310e8e0806008e836f86a44558b306bd371a9f..44219b7b61235d2bf881f5c3204321c628979709 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 ecaa769f12e68363d718f20ecce7437c5f1a92dc..addc55706a3ca903f2d56afde2cbaf9ea201e5e9 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 9f8446ccf771363ecdb74078e8d6955a62f61faa..695a85999270946751b3650906efff3d9c053a11 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 5eea02cfce1f6cfe4328a7b140ee9f97ad3cd7e3..3cbd65dee741b1adfe31fd728e78a49c0f12c62b 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 aaf27438cd815c45a50f11525db3634bf0c4579e..6018d877a8a6c20f5cd526c4d6c85fd7787bd966 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 bd75bca1ac6eee4f3d57cdfbe69b8d7e4f7da5e8..8eb0ff57925f3d8ecc9e45f3e796f7f3140474a6 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 5f78f1eaa7aabdab60bc7ddadb8099e226eb7571..34adf5789c982b9c3de6ef39f72a84f426dd6524 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 d110d4514771a85ca94a64badde1506122086f89..4285844420cb8af97392821435ddc0ac8975b42e 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 5c468c5057b15b40d20c13f8c2c16e6693b68bbf..ae7fb7046c93de6595ed98c7965b6ac81470756a 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 b543e9768e886c47bfc421e7906daf9aee565adc..687ff3c6f09f2885653e523d80e5d5fd5af30703 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 fdbf967812f9b2b73cccd7a1452768adbee47e64..76c50377f0feb32acabd128ab7c5e7b6e77501cf 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 2bb679e54dc78f474d1c0fc6f130d325be21964f..b5dcb78fb4f48c88c8d92593cabd3d3d3e4953ab 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 eb6e07ef5dad06c167eac44e544bc21bb529e1e2..8e4caeeb4070fc756e2d94904c6eb64f096fcb2f 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 cb62fc0a0f9c5a40fc807425379c8517cb6c45c5..02da0a883594b8b3e9ec14ab70e2acd658d64ed1 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 bae59e5153487f5c7fb91252fd4b2a433b69630c..19856e806b1f174a58707d15235cf423fd3d66b9 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 3c8e26aba406ecef7ac63667c87b82861209e2e0..b80c5b11796bb8f9e8e8a80f871b29db22c0ce5a 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 ba42b4d2a9c4ed0089d7776c0283dba0ef72b86b..426f68b8f0d2b1374d222b0244a6bc7c5d87d5a7 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 53d3bdf21a6f30334dc08ef47116108b0d8fb7f2..3239d37087c8b1ca4ab30347d08d44662b328532 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 6caddd7834a189f795c7924efb61cc8e524aa8e3..5257287b4f4dcc0aec9bdb1a4fa2aef60a9a6191 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 e5f1153527b9492b05a2a2b7a9e5a81c5c84b89b..638b12ae6ee975abf6da727e28bce2635cd18a3a 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 4a4d17b44ba63a5f87c222374bfaa82949fe3421..acb25978a46c39053beede1553e7752b9cacb953 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 ebaefcaf5f2ae603ab0e986780cd84289fe8d588..24a9d8f783f019056a31cc7412c691976eb13b91 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 4fa6cd315cf7dd9ade675a0e624550eb8c2811a8..70d98c58ca97520a41a9853f35e5282824a92240 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 d802a1fde58fd13c60e282643d2b825fed9c7bc7..49fa814068b80ca9f290ef816b9797d73b8cb1bb 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 d3af1caaa73cf1da2d0f138efdcce5a6f25d810a..945366bc37ce051d274ee4d26b780a5604c3361d 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 12dfc58a6da0011d747d538daa8c62ffe57bfc97..07b585950cf96f561bfc8e7b7f2ae80683240b4b 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 b5b0c0ed02fc46d4b7e28944e891c5ddc47c569b..d48d681472d58a863f1329ad86d16b8b65b95709 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 fe3891106a6d631e2f68449eef234d8760e0939c..080e974914b65b7188b1b9ffb6f9546ca4e55f4d 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 65781477cac9ebcf6ed3f8ba0b88a0d1209fec62..c514cb735afd339ca26866a817367f8d1285fd72 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 caa8e2f394481d605bd24af98331e66c8c56335c..faeaf24fa8333d704c5836956b9293389ee0c4d1 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 4f2ad54af398b9584898e3be3142e8b1982a74d2..25c75b977666a67fabb1903a8fcac4c65166c3d2 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 aa45a8421ebeeb202087552c0de79132d0359c44..d0ffe0af5339cb37e0349359b8805ab6bd3187b9 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 b269de52e535d3ee9cd4ca7c5f5fe56a3e2f17a9..e23b39ab16c50eafbef213e94eaab916573cb9ff 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 7b06aab04ee63f8649b002ba0dfff0efc59cf143..b44e902ed338cef7cd523bdde3b89e7341aec980 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 3c65a9c02bbdc912f9066ef26b4fadd13446dba5..0f5dd4629e6f180b6d948e9f2df57de513c060ba 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 a60162046e5a1ec699367929880bedbf6a7239d3..301d327d062449dfd650a6198bcee77e3f69dd67 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 0fd84c93e72ba0904c156cce93a0abd5cb0ddedd..96346ce064aa04c6baa1e4032f2f87c5a6f5b450 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 4066b0a1450cd02009f67bab38840dd7335a2a62..6f7514be998f18fdcaba7b5b8b54ecfbf28e6a48 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 d1c5b31930437fa65580b2e6a262dca335d20220..f5c3ce5da70c1e1ee5fbb5a2eadad86dd47c0a68 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 19ceb4aa753ea6a2c51c2ca69411b7044bef60c2..3a0c3d079d507c9ba22a7f2480013dde0f00f98e 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 74c028fbe8f7d29202881876fb41812cf32fd158..2110552b8e594f8f6c6a07ee5162589235bfd8b8 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 0ea91a111da389cf92fe8a82ea75609b1b76243f..40313d17a242d7e43fdc3264f778f13ef3791bcc 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 76d61958504689daca57a3f422e3c33163421ae9..d2616af95ffa8568353d72c160724b2fad8dd3b4 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 6fea0e9482710cf417b5aa00833168ad79109c37..1056f615d0f9b2561768bf76c746f5e1cd1d7287 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 fd56c9db16a96fc0eddeeadf7137992e876d82a3..4a1ed9eff83a66b4c48e2244140ee7cc91c3a17e 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 53f49c6b2fcd8098fa5696a8e1605e95a543c8fb..19764c80b8ba8bf4b4d3ae32e4d56d34c0db3a7d 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 2693b554f4146c83814c677f443c35fb5b5932c8..d3c07d1c36e923bc97ae1a1ff411d3efc8380c82 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 f6eabad4bbe036fcaa8979f4f10f647302312964..733bb9425448ff6efc21497ed01b824b4d54cc2d 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 0f117ff1fbbe16b9a6f82a86c3be8bbdb72ff1b2..6b0446be6d19c902bb8e33d0fd2a94c23b2bc3a1 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 db553f2e4c0b835386330ec9773c219085b82c2f..9bc6856326518aaa3cac2f514166145a7ea1213e 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 e3d35695287578d93390a8e082b6121cdf6a9d09..99e6b1028f71409d380fbbb545ae5fc37d9be25f 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 da4bd5292b0a5ae75031d2a68019667bfec9874a..52a5b3156b28b23c59a6fd938a200cfb87f5cc4a 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 8a9d838af24e825640a98cbfe12bd5c105b1d38e..544e799d0a03c3bd9addf366900664d0aca72696 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 a5a5a5c8226a51d94558d4b634290dc331a68306..62fdd24ba42760c3252ece6dfadb3feb7bb58714 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 67ec336264e5cbde636b6bdec37cc833c39d9430..643caccc3069c5d56c5d636268140455725231e7 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 d8e7ad1ed84266db421d87c4406bef7798f9cbfb..5f950fda48ea3d08711ba5a906892ffe6de37eaf 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 052482554f74ba3014befb8e5ba5f4857ea6ca8d..540a7eed621dcc67c8c753233d036d5271af89c6 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 1787534487b4b473f4b97b8d1a410cf8a2d2b7b7..50b89340465b07940e0d2bc511d2db69b671a029 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 4e4e565d991c765a0c234cd685699ab90fb78658..4e81bc13e57ddd735d75cc3cf5bf5ddf46b0332b 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 57bcf5834c0c9333a6929428cc42ab9938fea768..9cec0d8dd0b6cad6d8890d9bae1357629a25f6b2 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 76c35f3c0208c8826ab7f2944320baa80dc4fc94..17c4131f5f62240c70fed4979fd021184e9d2b57 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 c256a2398651c007303082286304a3158cf3b002..a0604534430127a35ec334f37828e890376a6624 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 e124526360b23abf0e3843ea830bc158d0acb764..dc9e8cad7a743a170a6b7a3527062cd54389a4b7 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 c5ee04ecd1c9a1fc61322c2485002b0aec71a1a7..f3dc96a4c59dd0d5c1eb04ea71f3a4a0a1e036c4 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 aa691e4a6916165afc8766e88e38e2cecb2ea3c8..6f8f86f161bb00bf0c0ceaf04b97442a10bdf5cb 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 dc5e1bddc0852a171577af19b5466f47580245c3..43fe1ce538e1f21d4f56e5d15e696f56bebd92e9 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 2dad36a055188f6f6917a5094dcbc761071f2670..dd979ee4dcf10c6d9364867da7ae8a8404e68c6e 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 1c1a470d2e50f03201b442174ba3af205abe4763..9d4f1dab0968dd04d5ed75daf42f240dfe00c71c 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 49d0470f9a7e511135da7415ee095103a441ab3e..ea54cc27e645c26848b5a5bfbf1423dd76796333 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 2b5679eb5b4a7eb0e51067562b16b749dae52ba5..b5fce38de038c97d715f5d01db040ebed8fe385f 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 dade79738a2947c6948b0ed89946780c83d6fa84..89786c264867922704aa09ccc0cb51c368964269 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 a20bf274a4fdffdb443348baee76f03a63b90f60..6f56c517d850e332c64b32bbce513173c5e55168 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 129203597f917953901cfb23452c511fbb946c5c..2be9941a1f30e0136872c5d108e80f1bf3f60dbe 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 ec8455639d497f39db2ec6ea7f2f659ad7e79c7b..342c9b670f7ef5d7771899751dbe7222eab33305 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 c9d6fbe25fe4869f79649b0cf391a1e1dc60a23e..a118efd21d98aa5f233636fed267b59f80255749 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 3b3ed79cadd95aef1e0570418b05c83b690917f1..3fa3f2a578f069ca674dd4353b0827c09a6d8d90 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 d1c57edbe2b890891f63078efc014fb635fafc3f..43cc59316f90a0344f1b4bf2b5074aaf36cf7a37 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 184024dfb8b71f08beda279d4f9297e0f875dfa6..80a99128f5f3e97429e90dd3acebc439b59b605a 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 16af735af5c359defe7001e90afcd08a95e32c8c..1c180ead4a20b58416f765ad811d425d2c32e94d 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 22b839ecd5f02471f3cb2918436529d05d595064..f738e7f99e96e927f9764d1577a52511f74a4aa3 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 c557c9953724783d5ff61cc51f146639336cd6e8..61c69f353cdb043107b8d64d60a2beb88d78fed9 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 ab7d6a0ce94cacfc92a8b28f3f2bbb5e33718aa4..cc4383d1ec3eabe033037d517d4dbb3e9ed26b2a 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 c1d5a9d17071ba63fa1ab48d522ae35b84fc7736..b424323e9613449fe3ed7187b35f647aaed38f94 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 e87e6619695ee690e818cc3e397a91f68ce71721..1640906e3929f96e4546ff01349b04caefaeba05 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 0c387b6473a5e5e8b9a916c24e729258c028cd05..183f5cf887e0e2faee00790a83b5ae1cf5cb387e 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 aee2d362e88d2e4506cfecb4ff78ff5094e738d0..63f71b2a492fe913cc01abf09af523ea9f6cc32d 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 2bb9120883fd9b4788a6d253b41d1fd4f6aee6f1..f217b78d95a0457e5a4cc089cb1869e2651e0d0f 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 5445f201e284a8d2a14d60adcc3ab1f9287829af..c23bd105c40f4b363f30038b1bd8ed10c830ee5e 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 13910d205fce2bda7fa05d6287c2053fe35824fd..17a4f2c8d8b1af3b8779d06f5f9e6ed5bff9764e 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 6c519d8e48cbc88616ea3c82aa1a0ad91f0700a1..5e6d3035dc05864339262b2f005366328c28d48d 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 ee14594681718bf4cdc26cddf49377de1129cca6..f03a4250de0d264baae152ad64ef4553718cccd4 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 e4b224fedf5b9724d10540eb9ef20060599b866b..d1cd5de46dcf2855b60722ed93f036280b38e9ed 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 6ecbe925026d6132744eade5184da2bd39a49939..eba4ee0750dc61bcaed74abbbb7a791c5245b0b6 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 f422fb3c78bd72a881c4d0d4b1da06a9f535cda5..887c1692e05b47cef7b83e571388be6ba3b1890f 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 039f7d71c537857cef07ba31acd8f1e29026409c..ba6dec774478e9d57321d07983ad1884bb29078e 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 51e295265ba625da7d41a592454075d2898a4b63..f52a3f1d9a2ee294cb5a511b788bbf58d6117ca9 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 b29ba237fa2953f968864dc6376f3d5519160bec..8d19ae71e7cc9124f666f1807e8752e379a222b3 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 c3b8bbdb3ea1c3654414adb8a6fd28d213c042b5..dc42aa6ae1d937533b69af7c73ca23edb6d5cff5 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 501f482b41c49087ec6753cb67d945a47d3ce1ba..56cd77fd9ea021d9849b0e4ed5a1abc26bc9c7a6 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 38521c338917b628541e23af8ea4913ca1712eaf..60a00af250bffa233a56f7602f913eb52f0da579 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 504424b19fcf9981ceb1a1ff28348ba8e2624c22..f40947955675f098a59b8c25684eb8b74c31e8b1 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 987c454e99e91c86d4af2236744b5dc9433d8bfc..8a6d60569ceb55b668ecc82b5920ef667eb4b626 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 0b543854ea972bd6302692484f3b5efb85f60ea8..5cacf6e60e90b4a011f087e60b15cfb19eccf18f 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 3fd87f95c52420afb6aecfae366a9120b0d58df3..0a42308b81e9cc63af3de1754a9142caaef54270 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 ccafcc2c87ac980da5f70e52cfa89ad41a0cdf45..856ba97aec4ffaed85744cd22dce4b41544a2876 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 18f75dcc65d2129957cb958f7dd29d554425aae6..43237b7e1dbe1f5f6ae66b564d810556d9d9bc75 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 6103117d6df56e0033c96972e2756c8a4d0ad8b0..7494546d71b8eb5048ce7c1aa1527e27d4a49732 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 5bbc56f8779ee392bea9b9859275bf8bccccfe82..ff351a7a08767de193f5e6b98f2194baf974929b 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 2910ca54886e74930f78f0c6d565d701e5dda85c..95147ec7b96ae8e63af958a7453f231e6a084825 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 2ad3feed9725ea4d68d14250b2fc5a20f9fc2be0..a5a8e806b98ed988df64b67e4c030e7371d5a9e7 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 9fe19a3e1dd48947f8156ec89a0cd6dd253741c3..7d7933d40924f379b8c28f5c62b7cb995c5926ee 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 ba78c08a17f120ea4872e9a913ce79c6110193f4..565e2b5d06164c1f648b0d482484336149998142 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 b789c57d7e80ccf62bd9cc7dffb6d717c57f307d..4c1c81fed11ffb6d79b2cbe19fe0c68fb95f975f 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 d8910bf9cb753f0280a148cc88ec317dc7e69ceb..3c1ae9e9f9aa1a2bcc4688ac007801ccab699faa 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 f6825727bf7741501c32798ba8bb9e706bc5767a..d72fdd333050cd45042237942f794a41f9d7ffa9 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 31dfa1f141f11b53b3b5b9828eb6bff5ff15b276..234faaabdb8208be823dd0fe80f66daa7e1e2cab 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 df00762487c057e47bc43f8b85198e447a2461ae..1e74a08e7cf1fd2d2d77b11bf99d10661467bdcd 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 95eaf8fdf4f23b17778abcd2a2d8c1ca291986ef..d46876edcfeb2a8c83e4017b98fa1c8a9f3a3c3a 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 1a27f62589a282f6ff7ff1c624349c99821a3f0a..d2eef7b4c3b7c32af0508cd4b23f7eb724490045 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 b15de36e32e04e410c6138ef7ec4eb11d9d8c40c..b89d0e0f04cc2d4ef6de8dcec8794c2a159056b3 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 8a862f718d5c0e36055b3b481bbf75112cc07c43..eee1998c4b189179b6de81f2fa98717bb5395176 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 181a32a6f391a0f87042028a33ab411f13f4ea24..685d771b51d410cacfa4bfc444426f6b6c268cfc 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 b43d6385a1a092024f63b70673bbf2822d9b7d34..04eda111920ec4cae3d41184cdfac9afde63922c 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 ba39647a690c3e37ed06b1ff3a9395302277fa76..3199977f1e73551c3d2ae27a246c35fa2907326a 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 79d214b7291c78b121c6b5a7d97823e0a5a39a2b..5149a817456b77d87e91ec7727deaacc005949be 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 e85d54d1cdf3989fa07888466f8b0a9a4b98d375..ddb4a973c698606b735dd3ae3b9820488bb87257 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 fcf70a3728b60451ce5153baa039f16c2b8d3943..43941eb734eb097492ede7daa1357653fab52216 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 10b56c66fec34c91fa45db092a48ee80dfa5dd6c..5668a44e0653b2685825ddb1b9105110d021590c 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 ebfb0bd5bef59d679c36cd0a2562145a11509f1a..33ad9d6de532342c8d40f86bcd123d23b1ea391b 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 e441221e04b9aa67186bf6784236486d6f30cdce..df3bcc0b2d747f920e3411972cc1462b7ad5ee3f 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 bfa1a857f3ffab6bd039e532c68fcf85c1afb0d4..890fa7ddaa7f36650a1b69a8554e5567fd674f84 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 417c7c810df9bd0d5396dc7a3f37470c5b458bfb..b411ba4eb5e9517082596559722893bed816834b 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 0277479c87e91f7303fcba6c9f87f3f2762319a8..0826cfdbd40637560a8ccdc77c6be68ba0e2f048 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 0a8316632d751563ef12fe6b74c69a0570286f97..3ef65cbd2478a5cd36ede984a6c1a6de39ce2bb7 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 df41397de478ef0412395535a6006e5e36580cd1..7f740b37700b1d91083f7f078faa871d91560e89 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 431e69a5a6a053361e3fe147775a35bd376c5f40..dfca33141fcc64f325bce3c51dcdc59a20df1107 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 d2f3310abe543a243304af3b1ae806728eff56d6..c1cec808571b63f498cdb0de6706163fc19b59c6 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 296115f6a4d80c02ad49b11470feb976c1f703be..509f6a3bb9ff125ab12e717aa5b77c37fe34d6f4 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 0d31251e04ccbfdec5e59bf586c9bd7b8651ad93..b416c7b33f49659d777df9f3bb32597af67ad968 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 79c3d513db7e94d3336d9dcf1fa809c8f2816a80..7cd7cabfa6c413688dec0f86840825b4f0041891 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 89ade213a1a9a66c3fa1b1956135456ded401f7b..5921a33b2a0766e7f6549d9cae36779309e0b6fb 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 b929c7ae3a27eab8c28c218d8f467e62ae91862e..de6d02f7abe2b4fc5af6512f3587a457970bc65d 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 f460cca139e239c066b9aacaaf8f0c22500d7ade..13ac36e2da4f0f2ea36e48c7619f369dde3239bd 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 ea1c85e3b432c67125d3b7c365270b553a9dc053..92dad2b4ec36c0f3e31e558191ee5e421473a9f7 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 8b752e8950537d4ec706c0dace302e8b00230f53..57d6e6ba556efd83d533093f09fef45ddbc0e523 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 e5aebbf5f302f06c7128bd9c0f9433d8e677b142..e6c48a99bd85772730c895d081328368646c1dc8 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 23833ad952ba3aa7ad64d1314618536790f8af19..3657a24913fc991c01521a0d7022e7a3b393e57d 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 83f4dd0bfd74552fe813646aa9abb71fed72ace9..4223cb4967646696afab42943715d964e77da3f0 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 39ed56214cd32c32447ef30baf1997dc27d2a003..2b400189be911cbe0d9ef8fa5893166aab9181e1 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 abc705716aa094fde652c3bc77c18210a5b8b280..d18c680aa64b34273075d9388413c954996d193f 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 e8d7a7bb4339e4ef40fc22cb433588c54dbd43c0..24a2261f879a16aabbf4484fa84952f107dca101 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 6f294e280ea301a72be694b53f3dfa1374b397c3..a175c1094dc8dfa0551b81c4ed5cc73cc87d16c1 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 605354fd60b1c5a110ecb4f4a46785a64980a211..f145946f659b424ffa5e79ec0ac3086ed6ef19c1 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 033ac7e6a70dbfe1fc28e71ab03cf17d43b45b88..566728fbaf3cd4717af9da3380c389592f67ab61 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 e4b27413f528e73a9f7f5ce1862b99b1cf04d455..6e59d370ef8104bd25794305146be6878219d6d2 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 7d1b8c82b208917e83ada929ef6902fed878e12e..ecc2de1ffaaeab7b2c59bf902a08c396cd4882b5 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 989aaa3b080d67d3cb4a431516737b4b7ba28f82..3d958a1a1a713718732ac11937279db62195c8fa 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 2754b4ce7136c65039a5f2b65ec36e4992815404..8faa51b1a520bfa6f9b6d42ab2511cae31cb2085 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 ceec8d5985d4677867de8ae6f525c06d7840ab5c..b5abfe89190cf28070d05c75bd3703b54d06a6b2 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 b8b3caad889ce0e7aafc0f6fa6d6dea149d3a6ed..bb4645a8ca46b6ac605aacec0e182447b794289c 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 27749ace2d939754c1cce8eb25bee996516c230e..26062d610c20d1c800c7dbde6b5b4c29f5efbab4 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 d8b67e150b129b04f9b64dc98bbdba15af0550c1..078c1fdce4932ebeadc4b0451907bffc08cbdfea 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 52f3a531a82f242334e4081ee3c39edcff7ee8e9..f8a79890009327ae5a652a01055110ad94955f4f 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 9e9caff905d52abcdb2048c6e580d1f17eb3cf9d..a7824a51f86d2ee99c2da3410d719f3a6be20235 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 18f5dcf58b0dd4dce209687f3d7e1e98f4e49818..1433260d99b48e5c47eefea74ab9f1f9a179d4f2 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 7bd81166b77d7833cbc1389e18ee65f452df4a85..0865dd44a80ad1ee48e2a02c75752f6aa23bd02e 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 bdb6bd0b63a67e7346a35e2f474a4dbc16c9c191..ecaacc8ed31185324fa6c8e6e5281ceedf66064b 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 f641342cdec09491bb856f114123322bc0446cb6..1359b78a624e6b56dcbea6bcf19c3be1960b3848 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 a02448105527436603d94e323788fdff60f17776..b265ab5405f9ae4b20a49945fc60c787751771fc 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 94d22551fc1bf1bd9d1c6f99649bd70692c5fd3c..88533938ce19512aa5cdeaa2469721b39560d063 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 2f94568ba385a196210660818c0df6bd3cebf972..236313f41f4a12ca0a4d78eba5526facfcb9f629 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 ab474b11523ee8f901a48dcbc18a3434c573e3d5..e6143663778fbeaf456a67044ad7a369c3a656cc 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 7fcb9f782931035b10fbeb3e6a50b897f6828e36..0ab8738047da699135a3a72d77cfa9dbeb2931e6 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 d95a5358f73df21ea3b1ba4cdea97bc0ad07c7ee..bd8d01f85a1371dffa8f32e522ecaa4ae5e8e23e 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 68d095ae28651320fcb2117ff07caadab1220c66..16e1aa304edc402d3565429c29ae48648a54b2c2 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 8b499d643461e910ffdfa4c7175ad3c4eb42fc14..8e41d70fd2980567f99d94d26280d573d08f4463 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 152ac41dfb2d91bc9424d1b01f28bea18e01afd9..d08d070a0fb6f5989ba64d17d2623a7dfe817dae 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 2192a2873c7c056e44f2a66a0fe75d29e29bfb50..ee144ff8af5b1195f08ce0466d0586231f3d0dd3 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 ce6445a065889bf4a4a459bec129f231fd854f07..8ca6d12a6f5701318d9665ad950d3be82f657e6e 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 5949262ff669ea9fefa49029b8dfae9fe07b8ee8..55f841a540158993e45ec8be2ad376c39a61cc8c 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 e98d7812da2db1d4dce76a8bd32a20ba8e96c6ba..80fd3c6dcd1c34ac6d10da938052bff2ef7c8aac 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 4a62045cc812f779b72d5feb5ff788bbe737bc8d..89abc6078703f218b48d4239ac60c0c11a1d71a3 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 4aff1d8dbc4f0fb1219369258cf5c62cb02673a4..c9bb93a2c81e277f17c97d1cca7da53b4bcfb6a8 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 f19cbeb01087c797a73184e4fe7dc8a93788efdf..3dd783b889cb9d4d43fb1064df53da61170768e5 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 2aec31a2eacbd30247aa72f2e7dfa1718a6fc7ec..bca7e92a10e93570842a7442fe4236dae986f4ca 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 8cced3609e243b186caedd3eeb79e338c6151a73..5e8e18222f922c00a646063b91599be7100feb41 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 184df4daa590ad1329ac4871d8943563397697ee..261af9e38dddf5cb796edeaa83614785ca66f290 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 8efde178eef4d55faeb91aa924bcc82e7b548a41..3996b9c4ff8d41fd0f46ebec5ab293661fc89dba 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 d67655384eb2a47f0ab2be0adc3e3a49b3fe45ac..173f5329d3d9ebed82b74b18f8cd789938b3630e 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 3ed738e86ea75be6ec43ab1fd828a70024c9264c..5faf4d1249e024a9455be9656246bc4204c80d8e 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 ec189d7855a0cb68d2ba5715efe94fa6f0c7e086..02ff850278b17f71377a01bb480e43f7fc304fe9 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 b8a15840b4ffd574430cdc5d0e57e74a3c116242..9118b42c70b6312659eafd76f72b97434147ac2c 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 c13befa311107d9b4447a63f761e9bffb420534a..b81a91d504bde2eff0a7e0da858f2892f3c57a69 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 47be961f1bf3ffdab3e99912cf87bf5c66bd9467..213ff03c8a9f0b9879c0b229d7aa3ced192160d7 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 043f97ad8f226f054015b72d04479aa5ac4264f6..29cc5693e05cc55dafbd7c00cc57b8476c7cbc41 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 fb5ed97572e5fabe11609a3c01367fd26ba280c6..56906d15fb55117ccbe2c3562f28cf3244ba5c99 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 737bd77a575daa3fa0e83fdde8de806870647b65..fbe96ef1ac7a42dd2bac48a37b1a95e9801172d2 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 d7c9e4fca895313da35669723e84a67e3a22623b..69ff7f8c86f5090d64e5ba6485fe922bde12080a 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 03959dc86cfd86f08e6eb1d83ccf3cd6eea5aa84..194ffb1ed462094593b334970533f5ccfd24f22a 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 cec49294bac64736cd6b90755292d1718b982b06..21f3e6c4e4d6492763e14011a7befd5f30025aa2 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 564aeee1a1fe728caf1137318aadcd75467a0df6..247de0faaeb7f22df485969648438d8cf601ec7b 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 fcf13ef33b312020d744cd99898294f02c1ba72a..f36f0730afabde6a790e177d8189ab6a47346abf 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 7dc248546fd4f95b5c80157baf1addecad40a35b..87062d22134da38d22dce196f28461ce22d4a0da 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 d809671c5fea79037e17f0f9820b7733162db5b2..40b5de59711299b608f45523f5798bbba135919b 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 8e3bab1e0c1f693394c849528b6eb9e2d01a3c26..3a29a1a8519c6bcca5d3de5d58de9707e0e3272c 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 e3d0c1c251603315ad20c121dde0886d810a65ed..9e9c232e896fa073eb17a83c2bd090c914d1f5da 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 cbc422032e503237776bedb6533c247e4d2fc211..9d18c6e6ab27d1b7e050a6ae77ca5b73f1f38e63 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 cdafa97f632d5493f4a81e1330fda9e975bb4ede..9da7e22848c98827c43863a19c7da8259c4f6aeb 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 dc42981047c9130debba45d4bec340cc3a2bb51a..ccb4e611001da2af0f17d8b6008a70341611ae31 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 0da68df259c8600644db989f247904822002e9b7..77cc36efae9500ea94f7109f5d7abed19812275a 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 4f8b8a08c914697d5af832c76be52c40b838b996..ae8f60f6e6a5e092bfd314e143fdf6816079e912 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 650240846ee22350111523a74332b613483372e3..4c49688a069d1d5d8167696c6f3e91ede28fa3b2 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 c0c4dcca6f3cbb12a607325b4ef8773704ce6ff3..905c6317e0c350cd006ded57a16f109c22f11853 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 210181fd98d2e9d6e850662becf6ec08f7b901c2..b457fdaff29746a0e70794b06308289290b2baf9 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 3965ac0341eb14bb35eb69ac0d9f708603b2bcbb..1425335c6bafdc0c30bd6f1c8efb8322f63df59e 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 fbcd349110258114d4aa630a86e35ad6dc19e80c..a033f7d855e06eb6c38658ce0329b309f81abbf7 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 4511e27e9da899c406ee7ae3208d6220ece4dfcc..d961097c90f0ea4fd0642e0a089aa9c7b81509ea 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 c26228c25f99df1f3f0ab60a18a6ee4e58e1276e..c158cda9e4b9bc509d8e7fdf63fc6846fe8e07b9 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 69fa04697793c5a9dfa4f3f00b1e2cb194c91e1d..5cc05449281c88cd0527436c926e47716bc3363c 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 992807c9850aea3d2c9ad963def66b0b86a6ce12..638a92bd2cdc22726715ad5a97690e8d89180381 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 f88a0370659fe3f5fdae1d1c5440d592be4a2c21..d5a293a707b6fa7b102fdcd8978d92e14ab8202d 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 ef4813bfc5bf1c775162672563a9648bbbc1fc5a..b015b00774b217c2e42b27920e34c25485615ddc 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 4a5c9b599c577f44ff55417537446881c9c52aaa..400c40bc43a6fb676c21249a4e84965a1b16e38e 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 98deb5f642687af645f3e6bab09b86b1db416492..03bc59755123fda5177c29a3a66a02d450fcc114 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 121782e22c01d3dafba32443860a43fb2f4e1dad..9741cdeea9d7aaf772ae2c124dabe6bef6494d87 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 294158113d62c19c69122151c4a394013162145a..dafc65911fc02625ae49be7197cc6e164fc874f3 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 3f79f35d0b19c318c971b941a787e972aefd7054..248cd7a8b163b60044ea390d75bfc2544c813aa0 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 92e764c54154fcfc3a317758f5ae319d3ee23f76..7a264962a1a9c303a39f1802f499fb0aedbbebb3 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 607be1f4fe27b6be2e278ed88d625f723eb858aa..0a57c2cc8e5af2ae7dd5e0b3c9a3c0e5191788a3 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 66685e59241a37d5344bd411b91990fdb7e2d813..7bd5f4639c4a2f46b74663e421fd65d298c43384 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 4a88e1ca25c07cbd79425a99b34389a89891e22a..bdae62b2ffe0c7c955c2a66f360b41ff6625ba5f 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 9465fb95d70af83dd2e06a42a4248b5198f6587d..344d523b05023047c6fc5efbc9b260ad2f098f05 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 257efacf3551ab02fb67261a04e02bcd36dbc573..cdee3af33ad7b307ae9b3ec9b379b0d8875b6a27 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 ea06f1fed6faf28017a25fafd38f1fde89e632c8..2ab9600d0898bc2b85e7663fcfe86551d078925c 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 48f1b2dadb2460c80cfb4b1c31c84324da83e9e4..ffc7cd422874f9b8e886763a7afee7deea999487 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 b7c86ccd50b4fd5549d347fde717dbf7c8c40911..62c57ddc554e4cf26bad6f680784ade644e82a94 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 a3cb25cb74f833a3735ea4ca5eb876afd5214a3e..d16dfc320faa8930a97d6feb285f9b2431264378 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 93b7d6a30aad4cd8cad8744cf2778ff6e97f8da4..6cf6fbd39237633fc9c8afd4cf7959c779a9ad63 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 cfd9add10bf48f7a2f11f93d882c78912ff95c50..cf7ecdc9a9d4d72594c685a44c058a4751217dd3 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 6fa16ab31e2e60a3c8ff4675afd127c6cb33de16..70b8c8248caf79f6de106589dac0e8a6b0e12c0a 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 7fdbff23ae8b23aa047c4d88ef1021ade9ed10a7..d6b3fef3e55b0367c4f4d563d3f6e17dee3a9c1c 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 5c5b51bb48efefa778a71b5ee1f0ad82a3bd91fa..a1fed56b0957991306dba0ee8d066d43493d67aa 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 249fbee97f3f354c4780c75e0d70d4d10a6b3365..4c3de777ef6cf691abd606d0b98081c6f10143ce 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 3777af848a355bb7cbdd1d24bc2768dca983aa23..d1a0a35ecfff32b5768d4840da16ee7d45610945 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 39fa2fc1b8b767e10d37b6bde54a696d00de9f0c..2a01ceb71641f672906f2f9f6863ee6835450f45 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 7475c4f64724127fab2f86697a81492815bc95cf..10fc655960141c01af6f8b21529a7fdf5e66af83 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 a4a61d6b82a16bf253a6b95b38a27236f9350504..65dc19ca528e1cc451e041766b9e8e3a086be385 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 59cac40aafcc13be4623a9f6c3158d97d6cbe1a3..4d571a5205e24fb61183e1d381b3cc3b830e73a8 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 0027092b1118e53222eecda389c71e91a7aaa0d9..440d213e1749d5eaf81adcd2840c18d0ac1cc3da 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 45e3526cedeb6d2989504311ce04124819b6c3eb..7d88732c5bff5063f1ac8378c85b22ec29adf775 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 5e730e9b40ef5deef67aa45f90dba2e6e83941a2..c181b2a0b9d3956ae2c5c7faa9ca67b08b9179ca 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 49e535a31771af081a394b67a959b4aa96507188..c7c5ec1e3af2791f7672d2d8cecb5308b1348f56 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 8c739bd24acd2da8097509822a82988dbc8e4248..24de64edb674baec24f0480e40f45f3ea73ef2a5 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 ca917ca54f6d2893a35d894c8f1580490f78e0c0..1ca42a6fd4807c892fa637916fff8d4c3aafb7de 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 7d031911d04edbf24acc722bcf4cc3d36e2d5fde..67279c6bce33845952a4e1547affcc55491a993a 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 c1235d5b9fbaf771030b99e4437a1fb2ecdb6ffc..9bb123ab9bc9876601e5415b82902f3ca978392b 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 51bc062876034289dd97e9a5c4a3498afeaf7f81..a13a98d284f22ae3bcfabe93843aaf30fcd25e90 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 72d3ae1ebc64d76f578052f50646d09823817926..216edd5826cacdbfaf5bbe2903d372f235d229d7 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 d680bec62547e1da945be2982c6d4d056324303c..405e835e93dd93e0de7f26098ac1a61bd401d808 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 1d8461ae2c340324f64c7796a5be644037f84ddb..4b3a049561f373d52958b0a0e80ec295d63eb4b6 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 5755f0df002589403366a75acec50a40fc86b955..f12d806220b4a9c1d32abeaa350f4c705f98a509 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 7643716b52997e233990fd0217003ddb42a31e8a..302eb9530859fc5de214d26bfe1f4f735c87768f 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 38d43c4b7ce547700e007f6f406d17f2c65d3ca4..bf988f77d4006717b23617f0cffe99ab325a228a 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 e51c9464ea4267281f2fff3cf830603e49bc3d46..5b6e982a9376b3406c9d336bf3d1a7620db59487 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 a0aaf06353596cc35058236f0bd511e613dc67f0..c1582fbd1150326e070603fc537f2f283e59b365 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 38ae0fc826cc89cbfde994cb2a56f030e8a6fbfa..8151dd7a45e8c019a9c45958ab3a3c6901c5ce60 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 d7abde14b3cf50b1002665880738bc679ee6ece3..9d27b76c5c6e043f2868c1e19f0967cc0e3cf7f5 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 676c296103a2ff91642bc1e9cc87b1b5fde13671..a3179fea38c87b51ca54c85635eff0acb86a8d61 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 8ddbecc25d89ac6fbb2bc1a385b569d00f2737b2..4412834db21c5a1b5fb5c9a6b8346a27410636dd 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 fe290243f1ce9fbf37619365dc6356c12f380986..4bd69d0470365d3d837ef19e975cd98476d60eba 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 aefd84f88b596c246b1dea2e066c9aa3c21af168..79314d8c94a446b9378aa7d5ebcb9a533e31cf1e 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 72c1b0cf406314970f324f3f27a4dab4659f64eb..00398149cd8ddcf0985dd363d24d66415196cdd8 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 59190d88fa9f3d237333e34c6f74e5fddc20409d..30790240aec6c097e6b557dff889622560f91432 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 7302f7501ec9e14281a7bf2fcd97eface2f6c1fb..c524088246ee33c5b3d8c1b39d7ca64598819572 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 c674abe3cf99dcb8283d96de7fa90549373c335b..a38d1409f15b7c0e484e6811c8637e8582dd0709 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 bf8a5feb0ee937a35ccd7a478e7c3dd01770b4e1..2e4bfccd4bfc44e34e85fa7520eb152fb651ce7f 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 9aed15a358b7b98b0fab9e6b02b6820cff9ff808..2fa26d0578d73e6a1b06e900aca8fe87a5e89a31 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 12e89189ca7dc9d7482822c9a1ce5858ac59a777..abc0f361021f231b9ba2269ef8ea8f855187ab67 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 edb7263bff403c05e02582837c45e4c30a32a803..9ee66483ee54de0d305a8c4e6caad052a887bfdf 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 0adf0683cf081f8439935793ebd7ed24fa2cc8a3..99941ae1f3a1cb489bf01bd334b77146c03c7f59 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 9af19939a9c636de2acd965c2b7fd7b247530c9d..e7239bceefd3ad347fba90fd0160f4b212b6378f 100644 (file)
@@ -110,6 +110,7 @@ struct au1100fb_device {
        dma_addr_t              fb_phys;
        int                     panel_idx;
        struct clk              *lcdclk;
+       struct device           *dev;
 };
 
 /********************************************************************/
index 0b2434cc4ecd4dbd6dde5feccea26fbb42ee5a1b..152fd29f04f295509b3317f899e0fc7675e4e527 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 5ae74d5545e65e91ff6d2867efa03e0c5a22392b..f1fb18afbcea035ce5b1bebc0df13ed26ce6a6ee 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 ee1ec9867a78ba4446a37735daaa3fdfef7da415..ccb753a474b18c64799e7f6445a67a66cf48666e 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 e2ad4481635996fb98511eccaa398177c6e618c3..921291025680e33bff12b4b5b5cea3151428454d 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 8023cf28657abf846a115130418198bafd806f86..96a770938ff0a02c176579feac18f93489ec5de5 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 469dfbd6cf90fb623af99c790be967e7127851eb..4c339c7e66e50d79312e00eee4c82492be5accab 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 1ff38d8036e99a9c1e1acd0ba34777f0ebccab99..2f5ce7230a43e88a1a6ffde1a528a370b8ea8595 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 e7df65d32c9181f74cf337fe181876f05f87bfe6..ba883a80b3c04db30fa08f8f21eba9f569c02598 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 bc57ae9e29634caed1190963d1f1520259858b5c..cce9ace651a2dbce718bf0d344cd6eae095fffd5 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 c1e581dd32f52b3636e900389ffe1876a0ff4dd1..2d405733a8c6e75b2ac0fa16cc129a138e033b65 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 56ae2f659b6d6e9bd5b5f792f1588362ca72ed3d..cfeff1b8dce000925958930a7f004bd88b44bd9e 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 2f078b77fe145937fada488e43eb7a12cc79161e..c1dfc97893ba59f558f929fab92e8587e843b2af 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 b3fc5fe26a1ab47a1094194cb1835c6b18d2aefb..83cd41fa2b01ad4cdb586b8a8c1a38db53f0b7e3 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 d57fa60dcd43603562d9a12a8c100b0f276fb6ba..ed1b65a6c2c3d050590b7c6c011cb027610e7e9b 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 5f27e1f7f2d65a4bd40ffd203f1e58a4315438d7..fbe6869a3f959172ad55744eecc673a316e45714 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 d18cad28c1c3a0af802c4c35775582996000f664..00dfe17871ac2fa4c98f23db35010d89967de96d 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 ddd708b09fa19766f3649c13a6be944787b03db2..93e4ca6b2ad7a9185cefc973d2240dccd3441313 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 1e444fe1f778b1941ff985b655db5d11a25a0eb1..042b688ed124a98052cf61ade8c996b4e42eb118 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 0e941d42e3e9d66a290fdc6229a3eaa8dba66b87..d6bbccb0ed152fe9b3bbc025b30f9b7cf079a64e 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 da1173a0b27492876c96717b7491b2fbddd23abe..416d9de3567915f4c47498002f9f62c50ad11d62 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 4c2c85a223acd5a12b34839b5489c6e3f73995f1..afb8340918b868438e188de7b3b5052845d4ab71 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 114ebfe309297396ce3200eac436a4ece8bad47d..3951d39b9b75991d8033404fa4e319da4c080941 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 39579927ed84b5185e5ae0d87df433722e863a91..afc66a1346d3d1622b973d9dc88caac55df7683e 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 ee3bc0c96b9dda6fe17f0f17056c4dc7f4fe30de..e9e27a271af0b003e2c2c3e01b2423504ffa72f5 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 0367c0039e68fd7ef25e102d3e0b2ab85f198132..1b853fb0b1639f6fb123954326bc886606a6be01 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 74648d42c69b3ee2b2bf0397a2fc85c9d6dd3a6f..442f7ef873fc368a3b33e867a90e65319e8b13a0 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 ed70b68b2b382c6886645dcb5ce301b573e7f5f0..a0eef95b9e0ed0760b3bc56056c7a71a3b766ea3 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 a546ac8685ea64d5f787d9b8c84cfe1e9a009e48..0ca530afc684ee622fbff18781e432420c1bc12a 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 99e9a5c37b7110eb2d20484c87ad78c0eb85f225..7706049d23bfdcdea6c1840c458d8ffdbf7c1266 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 59bc460178554af32108d8409cc637c424ed223c..85a1528f319f27bb4e4614810c4bf885c3aab6a9 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 caf77fe8ac073c56a4bbc7f0312e4cdf5fca162c..e60078460ad17975a2bdb39c46614e263ebdb067 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 06b89a9862ab2bb42bea7a067a455d497fc73e51..17382da7f0bd934bc9de9cc5c96e7d06a151e86e 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 45b45f37d347e47f8e5cf3857f5c2734a6ae1d98..f8d46df8fa9ee5cd91813b2de5e735e39a2ad4c5 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 963fb4571fd984a75e0f32fba612c416a4330db8..6691f526fa400b18aed0f632c6bee9106f10ce15 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 404d2462a0fe625f08ec04a4a39df6d8cc7100d8..3613efca8c00ca3d43a157aebea86152c1de3706 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 ccb02226dd2c0c28722ecafd61ce657975e441cd..a33d7a849b2df8efd97d4684017b770070ed2858 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 0f77f92427515f3062201bc972efd2aebb80bea7..c5b99042e6f2b71c22052e62a6698f1c8d86596f 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 18a038a2a9fabf02f015094faa0d99a38c44426c..a18b2a895771d9282a254dc2fff14ace550ce380 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 e04f82b3f4fc82ec0e0c943fb57970d55ce89f5f..783773e4560de98a1db31e48a11c7ed89ccace62 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 8dee063c833fa8fb2c6fedc91859c7600226fe8c..a661ac32e829e7cc9d4393c572c0215c96cb0107 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 429007b8036ebfe6e65af989b2666be4bd76610b..b74602813a0553043af68e451af8656980fb9a70 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 6b959bbb336a30543bd24a87e92d7cb28da1f274..d95a681ef7c972a344c5afdc5ac20d0fc4ff52aa 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 729f46a3c9ee0b5831ee18b6e08278a4801ee33a..3aeacd0aacfd22bb675f60c44c32475d8b5e8f15 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 e791741d193b8b3623c3be613ebd61f432631e7c..b32c456216790e1bdf7c86c73e385a821ff905fd 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 8b0c2bfa90c1da914bd4c942654dd14fc6618337..52fa1ef8400b82440d7a4c0bb9367a0b75e3bdbc 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 289328831e24a68d6dba8cc95abba5b9614deb46..dd15b8e4af2ce8e57789363ee0441b8b9988765f 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 5e6502ef7415426b67338e0ed7210aaecc9b065c..ce15b9496b77e058e331afa0a4a1ea83c9c3011a 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 5f5431ec3d6252c198b504d27c86378200d75e2e..0f1e3b563c47209cd9a09dd1591f6b08d0bd43d4 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 4ed4b110a154e5bc8caa044d1e667e256194f5e6..3fd884b4e0bec41b72406cb36a49ff05a5cde090 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 7d8654a1472ef8802b4b4f3769b818d4a2843c2f..f8fb89b10227ce54d7267da042a07233bd9b331c 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 112d85849db1046538844009f35402090f02eebe..8a20ddd25f2da4b2b2cf6ad229097682dad006f0 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 a2dbbb3f4c7463a7e20b3306ccd345b1b97918a0..bd3d5f0ddc34e918027a7bf3ad2d0149d1bd265c 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 ba34dae8bd9ffd42a615453441f789938011b2fb..10ee0ecca1a82ff8c1a80e8c48cc60f7d63202d1 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 84831253203dda4a4926db4a532098ffee8a1f4c..76bee0a0d3087f3c7db87d5c8619558455e33764 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 72fad54fc7e5b0728aac7e0706669368114fec99..0a9a49ded546355379379c2529ef70c2f217953e 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 8cb20cab012b0089080bbeafb7f4cfa7c09e06b2..5dbd16946e8efa5e6e1a5c00ce201a292de02baf 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 9b96d79eea6c81247380142fb9db0ef1ad0c51cb..91b9dac6b2cc0d792696407c4aad29ceefc55cce 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 b428c295d13f8cf311431a2ece7bb72f3a44d242..5778d1347b351a16d3fba209e906a668661efd38 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 2fda08b2b8856fffac82a7deb3c48756f27b57ed..d510223d302ca1b6c90c9971dde4e3a121d067a2 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 d1348fc4ca6ddbeb8aa66968819a4d8e245ab7e3..0c335b51043dcf922e7c71d66a532f424131037d 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 005b813a56b6b0b89eb97761ac979824c0a90996..429e6a8359a55a82671d8e950d9a53ee50f7598c 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 f2d2689407faa0fa7d1ea015221d3695a0014ce8..8f17d2c85f40bee0009d46a150a1dd5949c3a5fc 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 7a3a096856a8d76bae5d823c5fb2dc54cb4301ce..f1b613327ac8faab050e19921aac9f1ef585569d 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 7f37540ac4ab607ccb75ae768b4b65afd167190c..beed31ea86cfa4f54df76221b45cb92be156ec3e 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 0784575f4c2a270b3cb11a67048113e1c81f26c8..02bf4a1774cc3e8f783d085d92c39caeed3af168 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 2234f7fd1f7c4f3c395faae1363863abd39e0bb6..7a7640c59f3ca3c31cbc782d80e1db2097202053 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 3d5d4b2b1356d824b7221ea89f45c8999bce2d4e..5c424a099280a4eef220eea1dffef6f333826bde 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 c599463d069450482beb40574b8c7c1967d451f9..48a3398f0bf546d0d8cedc8c11e76abc595d6715 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 dd4242be3f1f86afcef12af9dae59fd3d49c583d..de87cbffd175fd888f27479ffa0badb58d3868a3 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 c8af5bc9e9805b3b40576f3a565ba3f5df2c7e26..a4b58ba999278ae16373edd5544bf84897a41432 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 74d019694c7ebfeaf60d42ba66bc73f59a4f15c3..7d0c7c9013ce15068758b58e21d222a076b37fd1 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 9021e72e1f985c45d65fbc5fccc28738bfae373c..7338b5d4647c9d75b5429e232859a6b12a32c1f0 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 810f841494efc6f0c229befd10f12ad930911dd1..74b768ca1cd8823e6d22456b76803dcbe32b72cb 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 e22d6a11522010751c39583a449f39b463ff2ff7..064ce5bbc3f6c87db14bda18e2dbe9c02f22c7e7 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 b5fc5d3c7525b67fcc232fa4f800e8247c49206c..14207234fa3d72934b5c98472500f7752ca0fc69 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 994726ada857c701f5fb4cb16949fef86d14cd13..d6f7b299eb236d4b176e653babdb4f1261cb9584 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 f03674afbd30ed3a737a8e5747fa8e25f7c79bb5..158e5af767fd11119b39947586cdb364f4c6a6d2 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 a4647a646f078fa877fe5a295518ef0082e78a8d..fddbbd60f4343f845a1cd0bf516eb84e1f09ada8 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 a201f9780b353196b5247fc55dc7583513ae26a5..8b2f39506648c0ca5ffbf8ea8bdf23d474f2ecaf 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 a35c17017210f9ba78cdfde99a44c6cf8e8f044f..679a3c8e4fb39924dae0a1e2f37d4e1c971df810 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 87b1a6fce6281b38746d0a1955960bd0863af70e..25543a966c48661085cb0b7c3437d5deff332ed4 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 51147f9ce3d6a185acf919d8cc01b805dbca5460..502f6dedccde66de2398b9d7a7d149c4cef179be 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 4f2d7ee0d2d1906e17086029a8b7f6412ae98720..c010c1fddafc1302801ec6c6d552b19ffd04659a 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 c40fca98f2b78ca6505ef9e9a635c1884fb27371..77eb628ecc7f2b1adf1ffefc7aa7d7331f3ef9a4 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 568d90e17c17d4d7358ee56c544638a140538a36..465ea0153b2a34df85207fbb4971cda0ea72af57 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 01d4eb0e6bd1155f38df153915bfaf20b96406c8..dedca3da428a136f0ead9aa590ba9fed03ce2e39 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 36bf0f2e102e7811d8e8b6bee41a64cb64b65930..7907e6419e5726702b0cd8eac2d57a5bd48306f8 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 8e0a17ce3180bc5bd172252a86e748d5f8f912fc..bfbfc269807020cc91b1cba4421bafc732e76999 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 89a80b568a179a1ed251312a500b4c649092b706..7fbe8f0582205a3cdb31514d27cd94708c9b8e82 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 5b77098944151cb6f37e4516f6c5c02e28fc274f..2bb3468fc93aadc8a4e88e9f2aa911210eea7891 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 acbbaf7a0bb26be8e25039ca4fee2a64a0db02be..45e1a5d11af39a0b913934ecbefbf01c4f6336f3 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 14cb602d9a2f54109aeb8acec7b759c6930f9b1b..98412721f0562c3e2f20332e28f756df6eddc7a1 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 138c5b07d80373c76f50feace79f637f3dc35bb6..a5f10d79e0ddf5cae1d1bab53936cbd782bb276b 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 eb26097b6f70f4bbd05928347f6d3c84f410a2a9..7763639a426bab78773138f29db5d276f2990f3e 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 4f1a397fda6904e1923b21f6436c74d01a93f1dc..034ad14710d14a395ab818389be4cbe5177cec9e 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 6cfc494050bef21a675ab9aa2f3e5020379781cf..fd1977b568f0bb9a338bad5e95709c70504feb91 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 91831975363b927687acab64d73b3f76f10e81b2..b74a471692970b825706fd96843c402597d509fc 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 fdd9d6ede25ca74065c2b092c742031068270aae..16bb9a3286781fa41ad319dcbecc99f4af4251fa 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 8e6b3ba81c03e398d2b91c76c456760c2a97ae82..267655acd42681e0cec5253e94d05681bb9f2c13 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 b0c89f54d1bb05f822f3148daec8d56800f62c28..5de296b34ab1f618ea489225cbcd054bfd9aa7f9 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 e2ba2a3b63b20a6378283e35e1c58c939f1d2476..87a9747f1d36b905755070d9cd85f15827d9afb7 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 a9ff3cf82cce0bb0e96bfed46cac5333a6be36ec..372ad55631fc447190e3eafeb47aca5d7a2a1a9a 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 9fe949f6055ec32e89e08d3cf01608cdbb678f42..2a94543857a195e55cd96bc2026075ec7559dc7b 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 c441f41f14e8ffc827fe0b1e1f1245779aa27a86..d48fcf11cc35a40616423f8de015b60817f2b74a 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 3b0dce06e454f265eb7e97bb5712f0e10639e286..ff28ebf3b635d1940f1306006623a072602ecd5f 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 1f6e3965ff7425456ca64477a713573cb5e7943a..70eb941d02e4dc406c3d16fc01cab71e9e68472f 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 65ff600a8067875f3d898481e1ef2c271d55bdd9..4eb30d3570457a1d3aab5b5b3ba2c18b3d62d890 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 40ce5f3094d19d399bca5758b428177dcadd7824..7071ff98fdbc8e569c4a274bd9c3ccbfa8a5ffc9 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 356ebd1cbe82518c9898c2bb1a2befa0f5206c5b..baf0b72c0a37deddd4936556a985cb020bf5ff4d 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 aff82ed112c93c26f43bed5ada5fd4b82e4e3711..fbb18ba5d90538af2a34361981248e0a16278d7c 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 bbdae2b4559fc91d0e7f650fcfe6ed81868b5512..f1048efa4268053e3dbb39d6c9db1b685bbd7446 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 e3b3e9dce5da3b24caaa52389f985fc571803b4a..fa3cd8ab9aba34aa1a16b3352ea0d368fb1026aa 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 e2737e2ac2aeb5e31a997ee3ed5f3800bf5ecfa7..d1c77fd0815da89cca4882c7bd4c19efac357745 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 b39053dcb643976fe571a13db58202c0dcdb251f..b1ae572496b699b2c5e84b3f1792c850e32fae0b 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 1c6bf2105939f15534c95ce7531fc6715212da31..eb2be2a6a25a92927e963b5f7f5ae7469ebc0417 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 156ce95c9c4545de6b03cd638463e23f7fa4746e..67840723edbbc68dcde52eeb5747725896525abd 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 b7d6d78f4ce2f3ef263fd54d8523702045dc5c40..a6fb0cc2085eff66357a29411e1ae817da783e65 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 b7b9ce002cb97838d2413ad579d499c582fda3d6..2c79be4c3153855d5dc3425bc590c135fe7e4786 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 9c2a0a13ed61289b43cb2fbb6b86a29452c0323b..a53e4585a2f3ab6a88a5782a82820a62b971bffb 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 16731d2d684be4097277695d9d87937f4b5b0afe..afcc6642690a8d85aebab8849321b01c50016b98 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 585dfdb7b6b688f13d43fed7dd5878afedfbc8a9..033589257f54f8cb08b513f863faffa3ed3b134b 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 88fa11071f9f1cb76373668f1e5645dc8ab6201e..e8bd688a4073d909df133b806ce7d79c27e00090 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 9bb3c48843ec216591e9a00994d56fda5d45fb7f..c968b60cee15bf14d8d6d590db9e8e83802ce117 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 e7382c780ed7ec30ad13439a56752dd2097a27e7..52d03a3a02a4e4a8b21bae62d0871b494d642e2d 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 49ddfeac19f25bfac8b1b4ecb1d76d645fb1e1f5..272005ac8c882db9f84f68abb525572d04ef5ddd 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 fe9898875097f5cd8506f9664f636a393cce2e2e..04377ab75863033cbcb31312a6e6f5356498b3a3 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 e936b7cc93893061f11ac7338ad7a9ba8f01ae27..323592d563d520f9f940fc1913d475bb6ce90708 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 bc2dfacd2f4a01c83864361862442ab63c4a73b2..b82992f795aa969024ba9c1b326691ab93662fb2 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 ebdd0c6b8766228bdd04b6ad854413a15c88ee62..951305ecaae1b951d6435a6ebed037f1f6da053e 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 bc690f2409faab3135fc1cf857263fab99faf2a8..27aa3f2bc4bc4273c96ede2a3cfbc91bc8d7e6bb 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 e021d5133ccb42d7b51f916180420bb41421aa09..28ab3c5255e1875727e74655bc6134ca7ba5a858 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 f9acf1d436f690952b9e8d5c4f33b3109acb3cba..bf3e0401824658359c5758f032494d5e2d4f6bec 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 1b542ec11d5d450bb9e43afab396882853bfc78f..7f55eb3f365367a254ba78bfc191b16baec62f86 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 542aa1475b5f969b3faf98f92fa2121461b5d629..51bb9bdb0e847af138baa7ef70b3610364308c69 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 5d9de9b217266cfa0d9b9e054047cbb146ad9250..38529dbacd5566900a04ace644777ba879abf206 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 8ed885507dd82c9e5d156e434373f9e3630b3dfd..e6aeb390b2fb66db53b056b7738ec8bc35835013 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 5d1f8884c8886eedc81bb54acd90c8445ad62826..fc78efa52c94ed45d7ae25a2aa256bab5e70bb72 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 eaaff67e9626869b7d6b296f226bf4e2b109660c..8ea1efc97b41d180a9c79c90b82314c80598655f 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 e76a3e5d28d77dd9187495319717264895c81644..a08dd8f40346fae595b455e86dc784b90a3c4767 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 4e909791aeac48a9ca82c6eb5564ca8e2cc7cadc..e0641b7337b3cf27fb6b0fd4a5953691901e0154 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 a0ccc253c43d0a4c5733c28086c2475c7be5a67b..3b8260ca7d1b80525f6846a1fdded11fd112558b 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 83f4ee2afc49e8092d0d7b733b02f996596f0541..d12bbd526e7c02ff21eaf07c37a09d1d3b13ad51 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 a62fb950bef18acfe820098082a19172feeadef5..88221c7a04ccfedd9a78aff832dbdef3ffb29673 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 d51acc95bc005a61f92e1a594761793968f26eb6..4f595546a639b7c784a670fe31a7cd6870e8d3e2 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 adaeabdefdd33ad7ab35e55a64acd69a5a62e6c4..16b09b94144187c81c38e93c8892d697fd7dc6c2 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 64e31f87d4907ada7d775ef3e3d6d729bdceeffb..7a1a38b636a91b20a7745ca42264cb68c88b2079 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 44883e9112ad06b9db9bdee40a4cdd96ec8b31af..a43d1813c4ffe006a125bc2221809c5b8fbfed8b 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 dce74ec570389a21204e40ddd14d4e1f619bebf9..1afc58bf71dd81e7a9bfc00d062ce217fdfc9abd 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 fdadc9e1dc49ea6a245258feeda14e36e226a3b0..3d47d111be5ae9413ee28e5f1e1e8da0852b7bb0 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 a703cd58a90e678854ac220f5661b9fb55b9ee8f..1bd29fdc2ab586945251084eebca671c9ec066b6 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 117910db51b809ebeea0196182e05f0dd0c54611..f52a7b8256f96c7d5eadd58ce034c90f0b61299b 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 973aa59975e328af594cbf7d7853ae1eac80bd70..18876056e5e02af78d29f6c7a5ac24fc74c3b32c 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 90527b094878971f831c78daafe2483dd99e83d2..94c4f1de1922f31ea5f9ffe395792fe3a918c531 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 a38a22785a1a28e6a7a50b533c1103f5caf2ebd0..1e2e11721eb993381879b2458a894d4178a3baa3 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 07c11e3e6437c40658838a60d0cc8ca5807b2603..fc3f510c9034419465fef5b95e2ffa8a15398b6c 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 23cf8e2f25db66905097246387fd8ebe1d329854..b2f602811e9dfcdc577cbc737b473624a08fe282 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 9b47117180cb1e8baaa4c1ae85a72bfc285ec383..681758704fda30e6250eb3322a2199d7010d9928 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 e213efc194a1d6e2417f941da0be04691befb3f7..6d483ab29e6397e8084935f2046face4b624097e 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 d5d197f1b80f92d071a2fed4b01240bc65be393a..c962bd534690789c0931be1211ddc0e4d55a1b20 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 5dfe2b5924db4f41243a9ebca0d747a28a5c6820..0a33b4421c32b1b2a239d58842b48077b312f19d 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 708b4158eb903b40fe7d577148f4adee8bdb554d..93b3793bc5b31a91dc466dc0a904a71c549e8dd0 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 eb358f0f5e0ad1151d6d9e4d4cd7d5efb2ed58d8..4cfeec57fb05c30a0f2d5d27d7d9972ea0a5b08a 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 92a140c5b55e32c3b6b4620104b78cac7ddd68f3..8d4cefd761c1dc843915e91b7c26d5f5fb6449d4 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 dbe115b075f714007aef48b16e8b765629f6c284..c642bc206c41d8eb9a99aa1aff8b1561e7b5c689 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 f630389ee176b14a5aeecd7dfec6cfa9ce2d81b2..15c8c5f3f688d1b3e905229ab1d13e8fc9bf8685 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 f7ebaa9469997a66c9ca518f6b528ff2ae718a0f..99c0b1234c3cae488db442914729a974ae8ded63 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 96feaf8dcdec5600475a2f831d0d44f61437ef87..9eaab2eb5ed3bf65d573e86a9af7e5662d3a126e 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 8039e35147ddd015d228dd40a818253cb12b4da4..cbda40d40326683236022c3a30b976a72ba257ee 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 11f703d4a60568fff5c2fa3e93647ebc8424ca38..761248ee27785afe07be567cf9d4aa87705aa031 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 f62b03186c62967bbc8d08e541e318989a6d1503..45a1ea240cbbb0a0b3ded8fcd982169b11789c72 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 228821b2ebe0195db8be0a59d9eda366515f9a03..dc93c51c17de962794ad688156e0c5cc389de920 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 3d213a7394c5b747dfb5cffc17dfb3d44d66cf03..58fc820a70c6fc6ed131393e50de79e25095a534 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 ce45f066995ebec7c89cdce43c57db89bd29e96f..9fa4a7ee8cfc2ebb86fe5fc1216dd92b7e19f672 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 89e043a88bb81c078c43a0b173da745e6a3f5186..ad479cc73de84b52d8ae4b866fc075fcdc03066f 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 06d07f1e310b063db9b4ffd8d393f22d73d6115a..98c6a7a714276b11fe2cb373bca5c50c8e18465a 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 548344e2512833bbb82f141fe34aefed88a6729e..ca0849043f542657a0a4d7f531cf3f564421b8c9 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 d0b96e071cec197a39ea7cf4c67f777f1bebb046..c6e57a3f409ee7855474bb323d5037a6f96ab97b 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 65b32acfa0f6070020f5aec660bc3bba38d64bdd..7dcaec54a20bc368613d96ed9c76ace1dd431d53 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 90f65f891fabd27210e52a2c9085c677d12fde62..4a054b11011a076c81357a0281e5fa2156b2bf5c 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 5142e64e2345897b8a770f024dc594a10c009446..283df898dd9f6f5c02701dc99bda8f7d9f3b0599 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 d0df0ed50f4b6733d6bdd3b21a62c49402a94476..8ec7aab89044019c846f0082be199bf08f1bbd48 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 a1af984e4913e94e88b0eac261c5479728d8b24e..fb1ad448308156a1edb9e44630f7565b48223cd2 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 64bd8640f6e81dc6adba863883fb745554db73af..4fe85709d55d245fb65f72c6bd87866c1d5c5ba4 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 7dedd17c4813172239c2cef774b6c4ab3c068dd2..282ec5af293e8f161e9dd8d9ced18393a0e7d925 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 db9df710a3080c43a964c04d3869a1a208209916..1aed34ccdabc21f9221680c21eacdca4ab6f8d20 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 a1e177f66404d28184fd99a5711d2c6f0b5005c2..544c9482a0efec22883f168e670c1320ab06eac7 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 f2284ceb129f7acdf91874934c3013c6d9b174f3..f1372f9046e389313afa3101a9072d0344e31818 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 74ddf66f4cfe463264cdcd2d7ea1dd9fb11bb8f9..86f6512d68643ec833b1aa5c5ef4e12036e90523 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 2a6a895ca73e542c571cb47d3ac7b86ccfe7511d..16aaab06d4ecc55afa09f1d7880ef41a225ad82b 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 916a35cae5e94d649d6d8d181647ab870ce558d9..e93bacbd49aed89946e22effc1c47b3026ec865b 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 182501373af2dc429637b936c99542c5a2d90987..574a7a8b4736ba49b297478c0712f16cc8995c42 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 3d76a9e35870adad0a29b2a04e5ab4c8adf02dc9..5a8f9641562aa12903dfbe321846bb770a85a0c1 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 3d0e0570e3aa1b00bbdd5f9655a9dce8819ace6d..3e61d0cc23f8c6a2b2200a8d4fee04d627cc39fc 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 d0d37738412009355957661fe7e47a18c7522de4..fa55ab8b8d80ef7a6b93e70f82f6a38f449b1ab1 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 4c4929f9e7bf382a537daea2586a11d429fa707e..8e0cb05a71424e557e065bf6a5ecfca4962bf041 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 a76b27565a1898f5a7572e2e871da4011304084b..0b0fd10a36d4da80870e3d3734c6908acf721fa5 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 8381d34cb102f8c6f7541d80173c98d456b7e622..d99a0a3e5f400e767ff6f76296f4596bff6f7f58 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 71d216cf6f875e01516f15cafa673e0b3e0dbb78..6467d5e1df2dd1508f39aa9f3dc6df6ad37c2e5b 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 fa1c4fe2ffbfb1fcda3eaaaff3bd8a3b3b3d9b74..c9a502eed20415fd83907b64c2870c4d079cf24c 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 27081eba220c95247a24a417e00ace8d574e3d44..07a60e74c39c80a07e0c43c793d75025635b22be 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 d7dfc13f30f5a7a9828d7467f18f7737f8e40f79..6f7848cd5527bc8d32c840c44d4748a1422357fb 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 4b17f67c888a057feabfba771e058e51fe791be3..654c0bb1bcf8981c1f863ec315a409c0906365c3 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 614fc6886d24553328d5a08496e2cfc802af421f..7fcf7569743f47a250f0bf2356f7c040b78cc59c 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 d28fa824284aaf8198ad50404e86f4793bb70892..7985344d3aa619925a82312b4f387ee815e8f212 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 63d323916bba9e42dc3f37d81359b16a6821784b..3a4310d7cb59d4901d7519002f7eae03e5170ab5 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 74047bd0c1aeb44709ceae3ef779921778c4be0e..ff3c1fae53571e79d139e9117efc8ccc4ec751bd 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 1e1a0af1dd34d2dc96c7f4b7f974add392f41bd9..a8a06bb78ea8e3c942d3d6c45f25f5999ff0a6c3 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 8a822285b6718f417d4ab3c04a0566d1dac3566a..e90c1fc5b981a7786d02c8112995fdf78eee8b47 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 edbd5a210df22144ab810a67d88dac5f479b39f7..ca15105681cacb7c3677b2397baf729ca846d47c 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 2466b0f5b6c43f175c27e4952e1aed7a0698c607..00e9f5c388d366031fd8c5b713655a718c0a9287 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 73a64bf32f6f4a9214bebf2080d4a556ea634d1e..84e06805160f88d6d490153b3138e31a0c5e91b8 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 5e595948bc5a6ffabad05fbfda64ef5413d36623..fa5602d0fd7f6567bd1091f81d134144c5abbcd9 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 b5f82cb362020c7451b823c2ff7d1e23840e12fd..b880c23cb6e4ffd78324ff26a2890c0010f67d64 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 9329f5adbfbef28648f169ce216b034a64b7d3fc..13d1d3e95b888fb2630c784869bf932092a51666 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 6b736ea58d35402eb7e7975067a4303131cf3d83..9804efe525a9314e4b78a52e7c41c1f88296ffd2 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 6b2bfe81dc51be79b5b3d736dc3b8f0f459f09ec..322da69092909078fb16222877ddcf7ad9c1a62d 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 c81a5cd7c2288014da00c994d58f9d9fa2caede3..4adb6837439ac38fa600f0bd1f373634cef5bb78 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 c8ba98fae30aefa7013ebfa168fed652a955f3e7..b6701b4f59a9b5bc44cd66e69a4eb7d5b69a547b 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 bde2c9f56a46ab883fdfd5cb932d958838c867eb..0c954cad74493cf6fb9002b93101baeb7717e3f3 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 aa6b6db3db0ec953096bf9fb6ae166d9cc392238..5e7a37f0cf84856663e93e40a605c9c169f0ddb3 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 3091e4bc04efe1e6f4d9aa88ed7987a221f9bd78..5d72e88598b41a16316b09f0c50819b48ad4871b 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 b3190890f096d5f8717f8762e53be74edfdaa9d9..da7ad0383037bfb5994393c1f595bad55b1b6c0b 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 a7c0c657dfaf943037bcb6fa753996c32956413b..cd6c7210a37366a9e144f85f5e042cea4aa20968 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 fce38b56b962cf07ea5ce82b205db30dfe7dc2c8..d8288aa0670ad61a5353452f0aaabae8663f4a4f 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 3896dcc2368f8e19b206ef49abc6bab0f12852b5..e47530f30489deb04dcacba6aacf98c90e813b6e 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 680ae7662a78ef260fd4897b244b69898a239c5a..c4ec7afd1170a7550df8704b2bb71ae450c927f5 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 127dc9c32a54247be2b24ec56de1f2d91e82a6c4..77ed557b6127c6c23c00ea285ad9ce3fa0721dcd 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 7e482baa27f5b5e3a2bf5e89b80933f04dac3b74..8708e4a5aa5c37a29ea994d5220de49edf38c13e 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 ac0fcdad0c4edee1f3085aef91641f2f0a2030ca..5fa4db3c3e320b39277ad576946a1cc934b4ea6e 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 cc509743facd8ddfedc6c8946446f515a79dfb69..113883c4f202e09e2e435f6883d7f6b484a05fe0 100644 (file)
@@ -4,7 +4,6 @@
  * All Rights Reserved.
  */
 #include "xfs.h"
-#include <linux/proc_fs.h>
 
 struct xstats xfsstats;
 
index a14d11d78bd80cfcd1b34beda1d63f931b336723..f9450235533cc4fcbeab7c3f5aba5f6a38cf1e99 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 21cb49a43d7cb0c8c9945fc35cd71dc0e3fceb6d..763e43d22deeffc20862742ccdb4c13cbdd0e796 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 b2c1177c717ff4f0083a3788f02c3e6d3c745374..ed66fd2de3273355fa5e74d6e953e72c0d827bdf 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 0cc034dfb78608e23b5a6fea5f41b076c8743b12..31b3bdbd2ebad14ed90aae053dbc40589c0f69d6 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 ad7f9be130872c9e0664780115ba496bfd49e885..8abf4640f1d552af4cecc866c761b597d08d4fb7 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 cabda13f3c64168a7a33d01e37bf895f9e4a07a4..ddd0bf7a474026059a62710b42b7cf90e5757d1e 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 cb6489c22cad2015126b6e7b1977c1507b017ad5..bc85b89f88cae1cf58a4353cc050f179fa6a43f3 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 2464ea351f837bd185da6ca7b2e146e30c9bae2d..8094b1920eeff6413648c2af6251c4de1dcb4a0b 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 912b42f5fe4ac61ed79bbc729f5ccf094de66c32..d42a68d8313bdd5721f317a6c64858a67b13d6e6 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 c6e1c5704a8c2b0f94fcc56b7f4f8a34057bf752..64d7f171ebd32ae8ebe4992b64700d36e49f18f1 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 d3a4e89bf4a0ddb916ed4f5d395285e2e2188869..6ccfd75d3c24ce7207e336b5c3b714c18bdcb69a 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 7d65ebf1e847a9c07c0fbb8178b26892ad3390e2..b5b3a78ef31c41e0f057d8f8ab752a21ec8e910e 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 cd664a03613fed2bb504675e009574a9b07ad5a9..1027c9ca6eb8a0e0adb8bb1ed558e5eab6115e08 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 542927321a61b5e2ff52b30faca74dac268c1722..93d14e47269d1f1cbc18906de9edbb6ab18dadd4 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 091eae9f4e7434e7d40364567dc98e84aa177060..2e073c1c4614f2a79cc9452854da1cead65fb06c 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 9a63016009a1394f41beaff8323a5568b6ceab22..3123b5aaad2a15ef3652892372c7808ebc091dd5 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 948714c1535a4224be5b22b313fae671119c6e9f..8476175c07e7ec54aee9943e86371997ece0a348 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 84a9db156be7d93f8c927ac782ba03d72b6541b4..16c769a7f979e387f58d65e094f9531213ad1f8b 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 07e02d6df5ad9f24b262fe2d852e21235de8119f..6a1a8a314d85321f0852df56ddb60f86168753a2 100644 (file)
@@ -203,7 +203,6 @@ struct backing_dev_info {
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debug_dir;
-       struct dentry *debug_stats;
 #endif
 };
 
index f31521dcb09ad6e9b7d293d1503fd81958823255..338aa27e4773b5fdf5793b039ffd9c1b975a247f 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 fa5f9b7f5dbbced4b0d94b949338e6625c4bf064..cf5e840eec71a19c665fbf4641bd395572e8abf1 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 62a520df8addf3486fd9877bda63ef7a4d545e87..a2b68823717bc7269e4de9e8e9cef2df57743312 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 87c211adf49efa1bcaa0c25b7b953bf7213b8d45..068793a619ca8752607aaf243d71ec2e04129600 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 3b0ba54cc4d5b0ea9bc7a11d48b476b48e9e9e22..58424eb3b3291ae3183506d5d951ab425dccb51c 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 adfcabcba8a1e913b0160b27d6239846e78ac4d7..5eabfa0c4dee65437e733e29c7031c91fbde4752 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 6665fa03c0d1a851a9b838035d0780dfd018790f..c05d4e661489b3625a2e83874cc87d4a51edf875 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 6309a721394bf52f3ad578a2144320b4732e9cbf..8d13e28a8e0751fb34b49e2c21af5db04600e2da 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 9741767e400fbff4e94a56934187fb1920fd510a..3813211a9aadef0e2dc2f96267faf914cad2987d 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 28813c6f44b6a14dfe40e885ef30528ff594b515..a7cf3599d9a1c1133b8c1681a02f7c09e7e99dc4 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 1262ea6a1f4b91b45a88312ad0de139ce57747a7..778abbbc7d9407f6418f370920fc06b6482bfba7 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 9193f5f6b09ddc07c979d31b953af5761522b0c9..75f2ed289a3f364644918f5b36ea14c4f3cf5ef8 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 cb2b46f57af3a0d914516fe869d4e775ec7cd199..5d231ce8709be48a95040d99179613660297f107 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 205f62b8d2916b8d3ad9c92ebdfd3ed00aee06fb..4bd583bd6934ea87e0b178b07f69a5c480d1fa48 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 39745b8bdd65d7893d184bbfa7bae221cd0cc0f0..40915b461f18d9179ed15efd57aed380b52392fa 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 8d58386aadd5d1fee3fba1642133b9969cd40c94..6a0e420915a3cba73fc3cdf31b52eeb33adccd85 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 edf476c8cfb9c0ddc11da72d091bc0077091745e..edfca427831928abc6a072c4e0d94daee6d7811a 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 971cf76a78a081d7fc8d96cda096810476169155..46b771d6999ec1b78de78a037a46420c7ae88bfd 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 a61dc075e2ce962ca85c7d2a4d2afb6cd6b1e3b2..ac6aba632f2dd1ba2deb9c20ca8dec543037b249 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 b40ea104dd369819159ea1265ca6e20584ea4ef1..cc8a03cc9674617c2304417974fd8e9b6b83c1d4 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 d1ad38a3f048b15f3501f24bb838f75081efcdd4..c5da875f19e372b9a577fc7d6741f1dbd00a5a3c 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 eeba421cc671e1df35dcdb1556dcf2539e9028a6..2734008140208c94d9060a056a3440c9cb2cbc48 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 1dcb763bb610a85295893645fe285f2659532f1a..44c41462be334dac8edbc365c293d7014bed29e9 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 5ddca44be06de774c166d7170c049b5ea5b09dba..45aba26db964376d10ee7a97fe999b2b0698dd0b 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 114614e20e4dc634150bb231b8b9540a11a4abd5..7ccb8757b79da2e34c70844558fe23de73776c8a 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 f0273c9e972be6fdbcc32a93dad92091fcaebd9f..8cfda05543819a972de0853e76876c67972c25bf 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 dd0b5f4e1e45acaad867296c3fd28bf2215af581..f88f0eabcc5e1c46823ecec20519bee31009f7d4 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 8ec38b11b361e5e3d56d3725893093db8e6ae309..1d1093474c1a99e01c43f569f6f8ea42c2554dda 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 7ac3755444d3d5d6f27e246671258324429593c9..4a351cb7f20fc884df8720f66f0be9691d9eb6d3 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 208c87cf2e3e113ffcbb5bb7ed80922dab438bf6..c98a211086880a84c9c82abd5a6320ef363468fe 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 936a3fdb48b51ff93482441ab2a676e19460b5ef..4ca8c1c845fbd06e392425a9263c67b77073a454 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 2d12a1b187423cae51d4cc03ca86088fa01a6247..5f728407a5798e942ee1df3da3f47eb5d09c0eaa 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 ac3884a28dea690a24a93c2570e4fe004599cab9..4ab9bccfcde0fe1d86961bd167690129aa7cc3d3 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 507f7e289bd1596c746062a705455a9c4c5722e0..4ea558bd3c4654b00ce565ca2b002603bbc1e9db 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 4471cf96ef6990588364973506101023a6326b02..47e5679b48e15fc14cdd8843d24d3915c6273c3b 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 a713e5d156d8573ca3ee5a28a294054a23e4fbce..acf820e88952977cdcb2d34cebd8d0ea759f2117 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 d07992009265ab6a865ba70d0f20db21e478d5df..c696c265f0193e2a06127f8815e89714ca3ab0fd 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 9f8712a4b1a5b509614ec27157d247d28faa7a0f..b848517da64c3945e4f0bfe2fc6210ce801f165b 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 280ae96dc4c300d29418ececeb5e9b91acf27e2e..1099c2fee20f6c8abc1087e327142abc41ccc831 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 f84f167ec04caebe7025d37c7302566cd8f67b94..09592951725cc0b578f356c951348fcc48bfc0ba 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 fe0b29bf2df76822eef96fe08ec6cf9a491ca89b..c7552459a15f5763f6c47b58dcda6980f6881a53 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 3c202a11a79e1c9b861f4c2206660e9a5b477151..01e8037023f77d0883704de18b3af36af21819cb 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 6f260c1d346759cd8ba2e86e4ab74256fe97702d..6aeb711f7cd163837ceec80d20c75211b21a70f0 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 514414a5ad01db86351e17f722bde1484d2b9a7d..f8a8215e9021e1364832e1d6441b1e4b299cc9a0 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 a0e785815a64bd523be92bea960b6332f2b8fa3f..635d97e9285e3eb137a8a5643d19adcb843cb0e4 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 e429e5d92dd68e15bcb132366101b06f45e466c3..7ce23450a1cb4ee6ac5ecb0af20b4b7dbea7c2dc 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 e873ed97d79e4152367b15ce0ef26f71103fdfca..9a647fa5c8f1f095c66396518f3b2466f68c641c 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 1ff224793c99f9778f803b3fed1d1e4eed70227e..ad03b586a09576549c68f4993c69ac2594842e24 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 30a9a55c28ba1acd6a8130301587a4e347cea2ad..6eec50fb36c80b61e68edf1a2214791679fe3285 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 5e0b59422a68fdc48b9697a408aa578122e41633..bb2bc99388caeea596ee78f59fd3ab44772fa139 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 9449b19c5f107a73bfe7eca9fe875708862dc3b9..56c9c7eed34edf8869830fab1f2d24b71b5177c6 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 b57cd8bf96e2b67c6588716cdfbd92dba58d7b0f..97523818cb14e0676cdc22c6b748f5b643ddc9ec 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 35662d9c2c62d74f588a855cd338a719adc76952..bea46bd8b6ce9e90e8e1a5e3d11e5f59e06ab144 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 9c756b5a0dfe8b3103c2057002c9ae24630aee27..aaa7f4267c149a62e81907584cc889f244c86a31 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 4bfb5c4ac108d40d95fd0a471b7dd0f1954d4cf4..de2c67a33b7e7e9ed09eccb577e6b991731084a2 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 cea1761c567221aad0857e144f2fd0c9f172db84..ab5f523bc0df90a5eadd6ab92c3e9f0f3b4c2c64 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 ae82d9d1112b017ff3d88d92c72e79a33a1e0ba6..83d35d993e8c91cda28eb4f6f0ff222750a4a1db 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 911e05af671eaa41cbdec879c538754708d3e172..edd89b7c8f184dbe18617706f0e1d93e1e916fa5 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 7595056b96c1e197dc5bfd019874c9b81415c85f..fb19141151d84b9d16dc270c796b2f0f6548b265 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 bb57b5af47002ff8d3d738651e22be1b98020a06..bab27ccc8ff564eb70d364746e1fc317c0fd3fb2 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 53924f8e840c9e8f095a94d54f20ebae15fb0e91..6914475bbc86c000c76f4d050dfdbd4ab8bc598e 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 51e131245379afe953dccc915051d79179e87399..9b21d0047710e60ed2e08e2e7d8e034187b34f01 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 61e6fddfb26fd4c3d6870fd4ee8d451c5e10144c..6d28bc433c1cf0489ad4a8644f46ef74251af536 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 77ac9c7b94830b235cc5a39db1ac22b2d1ff2289..fefb5292403bc96b1481edbbbd249da939d9fb2a 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 9710254fd98c8aa40303e318e5851693f5e969a9..e0a3423ba09edfb4603026eac94fab696d43b2c8 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 b1424dccf42629512c9db94f7ccf39b355228d62..800d53dc94705eee89833e7db341a179490e14a5 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 8b31588460d566afa0942498dfa8a1c8cf727997..92b11c7e0b4f22ecdaad25bf5d66e2ae7fc61a22 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 aeb4980745caf83e9d60df16348eaa0385534c29..b71b5c4f418c5e5e5460bcbcbdb9742226ce70c3 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 172f15e3dfd63d2e7a5dde72dbe3e42a752e31b8..7c8ba9d7378b6dc2ef360c17e4c1d3160d8d3762 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 e9664bb7d1885678495b4b7520e588f6b7aa0958..4e2d61e8fb1ed6e1b9dbad130522de8e2542b9b0 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 97a0f6bd201cb17654d8a708204d000bfc6a5cfe..a5d8ae49198cbaf6f547a8e28f6c84951aaae1c8 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 0580dce280a1a40b84193528f57c22924a768fea..a0458bda314872264e283125f64ba19f6ffdc99d 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 43f09c7c25a2e552dba2e45332691905b407393d..7db2dd7838340c88c1b7b53d979d458fecc70b2f 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 e3dc031af7f513027ac54227225c22570447180c..1796ff99c3e9c76d1b17d98cb2c28977244fc69c 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 a0c4600250366a54e05de8b101f083f1d542ec81..1e1652f25cc19d8c7b6f1090fc5633011ba6f624 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 2fe12b40d5035a7b459720476e7ab7002b04c9d4..a7c19540ce21e6410ed3055cb5a27419a8f5d9db 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 6c0ce49931e500da0759804d9c54e1ed4687fc5e..8b86609849b9fa2571f840cf904265f0cd95ca11 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 a7e66ab11d1d656d8fb9f861f4b46949a7ac124b..c23f91ae5fe8b17c6176c91027b63840dd1c2a0b 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 67c4aaaa2308d3a9ffcfe38eb62b79877b516e71..5642c05e0da04ca37752aaa5e66e207b22f78af7 100644 (file)
 /* Motorola i.MX SoC */
 #define PORT_IMX       62
 
-/* Marvell MPSC */
+/* Marvell MPSC (obsolete unused) */
 #define PORT_MPSC      63
 
 /* TXX9 type number */
index 964e87217be4eaf9b73354fe31cd259915e1d29b..78efe870c2b7c85c9814ac90c04e137618bfd866 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 204ab9b4ae67e7d3758bab3749d6d8219b5a4a22..3956c226ca35a69ec83f8001b31fc90979e9b530 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 aff5b5e59845a837d038532259673bd56fa49ddd..47ffe3208c2706935d1cc41750af1254282b17ee 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 a81c53508cc683728572a11afb02fd49a4daea93..76f627f0d13bb3b2d7d0293afdaf476f538c9173 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 8c0a292a61ed828712ebf4a0e26a010a0eed58cd..0dab49dbb2f77472445c70f7e8704aaacc8fb261 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 2153f35245558f7afdb39f7e14e8e4b0bc0b7354..effb4c662fe55e3a3e4caa986df669c0ab6d940d 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 015e5e1ce8f113154368f6ec12b360b51c4c6a02..4cf0a40a099a55b403120bd4a83b76a07d2945d5 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 62597d86beed4c6a0c77265e91d0698bc14a3f88..52f32a60d056affde942667808aed6b3f1f367b7 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 5ccc2333acab27a32d49a7f3cc70d0dc50f3b3f0..5dd382054e45606608d1cd8bd88bd237303a0e42 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 060f563c38a2463e87febebde6d7d4986a49d8af..a39023579051d0768b759ebb202adf9ba4107333 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 d3ad482729249692037ba2ef085ce146da646ed3..9697c6b5303c5f9114ed361bca5ad131ac30f17e 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 66a196c5e4c3c0ea10d31ccb0f105e13ba4f3850..ff5803b0841c62eb9bba845011221f45b0d50f2f 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 b2a87905846db68ad65d62a6842893c35a1302fb..bfc0c17f2a3d411fcdee446f8aeeb0c1be0f681e 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 2c2772e9702ab4748e6ef6f18835cdfedc185310..b90e1aede74340942af8ba220a3bf5c7ac51ea27 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 f7afdadb6770bb96b50cd4285b65b887813d2ea5..1f628e7ac7097ab40e577904a91f26fce28610b8 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 7a723194ecbed71bec2db5265c932c2f84a8b123..a594aec07882d9a0ad4d482d00afb81e4daa3189 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 13f0cb080a4dc960a1552ddb555155bb97c763f8..62fa5a82a0651de38fcd147f93a2b10e79f0bb4c 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 feb80712b913cbb8f9e0cd79b2e766b5cc2476f2..63b349168da7255a13cbaadca263922a9826b581 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 6e40ff6be083dab77ad46edc01dbd95e4c0a854f..e5eb5ea7ea59824d8cbd6fd68f244657ba07a55d 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 9a34e1d9bd7f97eb82e6ceb0042c7f5502742041..9ff449888d9cda491a39b0ffeba27c31d47a72b3 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 93c26444451011f50a98a9b918e33069e95b0905..62c92e43aa0d44c647de96c7321415ec919462b7 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 445337c107e0fd347b912878d24f6541bb64d3bf..9f5433a52488c51f9bf86f49f3a0c17d6f973c61 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 abb2a4a2cbb2c54b547133a001275406c6744c30..cdf318d86dd6f9928acf34e55775f365eb010acd 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 36139de0a3c4bcb7ba7da936a8d43fba08aa5929..e6a02b274b737e9d46f6c6816488fef40c72fdb5 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 a808931808261eeeabed43c9b6df69917fbdc204..8cf3596a4ce677ca787e214d6f33b32a6d6b4088 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 e1c6d79fb4cc9f951a524c4535d7c8ee64282a14..2d6e93ab04783452c7ddd979c65ca83d51256da2 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 c3aabb576fe5bf27d1b0d4eb930e9234985ef449..c90c687cf950a4f53baa1aea1dc37f58a4645244 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 277e403e8701fc6491695f06275783572a62135d..4469407c3e0d46c4fe3b1f7415c28c88451597cc 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 d4c8c9323aa464f4a0f9dd347e0509fedb0d761b..4ac4ca21a30af2b8ed512192d67872bef06d19c6 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 8a16c2d498e9d644ef863cef34225579d663c63c..c60409138e1367c57515bccbd62926915cf25a10 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 3cb21b2bf088d58d909e9fe20c2ccad4396baddd..8186ca84910bc65e42dafbafe4bcc70628bb2262 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 9969358a7af5a84aff788cc49fe103437286c5f6..e7258d8c252b272b56222ca662ccb197f3bbdf23 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 5257f74fccf3cf97951bfb150700424ea3c129dc..9fc31292cfa1d0f458116f446e49926e36ed4a6e 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 f99c41d4eb545e395dd9b7256b92919ff9b3a5c3..f1e0569b4539b8b8e976f6aff26b79f016f2edfd 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 f2ccdbac8ed98a124a309b0d858808d706293207..83198cb37d8d93b6ac5263b16b4a9c72e5a958ef 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 3d2ba7cf83f4587e4cfbfffcf9d3d4db70da7464..21016b32d3131d2bf0fdd96ae782b1627925190a 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 e723eacf7868d2af4442355b37480cc6f6c36d60..42695bc8d4515ff1da2c4926a72174516fb09e48 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 eacb82468437813fb390641818a435572fff14b2..c2cf2c311b7dba0b055da1bca59bbca20d340420 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 cff20df2695e20d95038440f899826396cbd6192..db29e5c1f7909a537203870dc0ab98dbf8672035 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 e3c593c38eff6cfcdebe29bf1c9768ae9ad7331b..b63b367a94e803e032337654e6470e7c97be28d5 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 ef6efedc5921dd656929de47a9f22d14bceba6b8..0b4352557dd54643c05ccc52e6c48de6b42a5a06 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 fa6d792813681431cd96c68c803c294c73fbdd5c..82b6a20898bd1ca40a715bb98362193d802610dd 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 ac5e5ba78874661445a3cd8854f7c15844904914..dc0746ca1109d9e39ef12815dee138a76496ac2d 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 909dae445ea7138be46ae56020ede16a72c8000e..e8e89158adec6cb17e941289d4e1e8cfdd829c57 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 ba739b76e6c52e5584af1cdf46984a34fb6fcca1..83a7b614061f4027d030162d4237c4fdd5b0302e 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 2397f7c36cc723abacd3e6e1d28a54f0850c3d88..db7eee9c08863cae43a79707afb04ce0b649d5b4 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 8c94c89a6f7e4adcf24f473953c1c71f8cb1ffcd..fe5d33060415bfcc4eb92e993b0a2b99f628a990 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 ec5aad211c5be978332dd59682f9536cb2f54f74..f92fed91ac2360aa9dafef57f773b882ab6c4251 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 f1aa20ab8434ab9efb93616ed0b5c206f552907d..d0cf700bf201c9ea73909788e7c379abde7eb0f4 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 ddde097cf9e4106bc02ea55538926f44ed8e587c..43b7d875de3716fb20353fb732ddcc531b5f2b54 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 1a7497d015b29b4dcb7ed60a520278faa9ad5859..5b7430bd83a6533065e4cba76fb18665d172ef80 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 242fdc01aaa9650e0f9dc2d18e659458b1e21067..2277b82902d83a75fabfb9c2c2269315a6022b71 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 504c79363a34dd885eb462910e8e32971696bd18..616f9dd82d120763a876760d9fee6111767771f0 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 3ce956efa0cb804cfd964bbc725857b7aed5d7f1..014f19e76247c7488bc2f3a943b2cb7caa40f9c4 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 03a44357938675c84e43d3c5c936a272a7655fde..0e5f965f1882147307f0338376dae12e391e7418 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 63fca317265997166716842611daba70cdf7191c..0e987c9ca052d5421acdece1896b82f636e4a1db 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 9dd581d115658285cfbf77ffb5f0800ec2b89ca1..dbbd518fb6b3e91dc298956f7abe842361369952 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 927d85be32f62deb58da1029603a01e3a04e61d9..0f1f6b06b7f365ee65643007ec686a783c5148b6 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 ba9138a4a1de37f744eaf488fc0930b82f60b3e1..4f05735b02d3fb7a3a5ecccf601a21eaa653ddde 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 f045514d8d207c0bcafd7a0c1b19cd79411fec53..7e08cbf3ba49f705d54fa9e7d0f34f13992b8de2 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 ddf20bd0c3171a246f67ff293b978337608aaaaa..53bd595798617a2bcab2f483b93bacb0464943cb 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 c3f058bd0faf3e90857a762dd0828b621139ea5b..4fe91d4974362f53bedd42fcc3bbcd2424f6e279 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 513b9607409dc7054e6a5540424095c12a343ae8..b5670620aea0fce7f0029a73cfedbdccbd018f8c 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 d8c02fbe03b587835f4f08537eda9d70d47a982d..eb3e2e558da13d85937ee5bd547ffd591708bf02 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 f719b64741d63419f42a2513599fff55c1148130..eda2e2a0bdc6260a936976523d6b4204d4f2a3e5 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 bdbe8b6b122523e3e4a013a01ce6e02a30cd9699..1804f64ff43c1c3cec898488c456e2cd52beb041 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 8e3bc949ebcca27fb999022e65cde28ff2bdc710..dbd0d5cbbcbb57a5ef5dbe903382bfe096be10a4 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 d8f1aca4ad43696aa8f368c335a04c69918b77ef..5f5769c7db3b2f87b78ebc0b07425edecc7d0846 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 a39aac2f8c8d6dad03535dbf46f34e6fbfda2752..24ee600f913174c3928b77f2498192e472927da0 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 e3638a5bafff9b7058e4176973bc965fbb11a4cd..89c19c0feadb95374a9724af6d98f962c1b8768b 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 f7117ad9b3a34ddf3ce6cc12689eef6ebd155763..9df370558e5d25fbfb073e58c666b72bcaf8a165 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 43ac818b8592bc472b4b67e19831b404cc798aca..9057b8056b07b732052d0e318c7480382508f03a 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 58251ba63e4a19fb9262c6adb59831075a858dd5..6c49dbb3769e3cec85daf01e22fde098c5e986b2 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 84aefd9b91ee302749a9b480e6164f53bfaeda6b..7f421d0ca9abbcd3a17ca467f1221465537d982e 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 cd04dbd2b5d0533c1ecd3919f4b067ee9047e693..e6c030e473649b7a0ee94cea464d46f6c352ea9d 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 85245fdec8d9a34ff74176da9f0d6b59fde901b7..8368621a0fc70cfc3743ac36b04b249aaa4c3d09 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 596ac98051c5a50a460e8fb638e967932c5a86a5..0789a762ce2f49add4f8823c38ba366d88bda9e1 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 9834c4ab7d8e86e1ddb5024b28cf1ab2ff2e55a6..68575a315dc5adbbd5f1b3c7b80a359e9d8036ef 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 030a544e66020fb6af8b0719b551c5848a55aead..4fa8d84599b0bad60d03c87243c9cf97ec9bb52e 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 910e02c793ffc273d4578b2c68f47a0fe33b8412..f8e3dcd527b8a52637aee399050ba6e7d0d28b64 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 985732c8b025eb0c4064a18243114b25b34e5e87..dfcd69d08c1e9336d173657425b8017aadae5fb4 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 0787d33b80d83f1dcfa0fcddb8225f0c859b1402..db09eb3669c5d9ca630d1cea5ea66d85e2dea70d 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 2412042f55503f1736101b5b32b599b828b5cf76..0e22744a76cb6582389c76e37070752970114f00 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 549938af02e780493c7f8ac4deb8a322ff1fafa3..a3cd90a74012be927c838dc1e9916f78538948fc 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 29420ebb8f070acfa01c11b979285ecd6c2c82a2..3963eb11c3fbdd841197f9d9ac7f9426db52ecba 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 91f9d878165ebf16e49cdeb419a19052ed415b86..fed9290e3b41f94a566df19203f552d351e99c5b 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 1c811c74bfc0f3123eb2ad481822aca91590c997..4eeea4d5c3ef4bff5b6bd759e0e293808e0c6401 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 63aef9915f759bd447fc6ae365367d2e770afad5..7cb992e55475ba4c930f4b4225c60dc3d0932c7d 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 3f9ce609397f142e8c4cb3e5c51499fdd1e4ca1a..0f7ded26059ec6261e704d37948f736b1f1c7778 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 3e073ca6138fadaa75ff3a948de64ef45746123a..d57b0cc995a0cea45d82bf73d8149aae9f7b2e17 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 16449d6daeca214f4bdf979953a2481f29b52cab..293d56836f01cd3052ec6b00dc39ce03f085ec73 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 95ebd76b132d35c9bd01b777d88a50239d4dbb11..707d7aab15466ac4a926e7d9210a686ef49572ab 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 2121c9b4d27567201c2b13704e917f1c2b05f141..48fe3b16b0d9c7903156e19810a5f8909312a7ad 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 d63cc8a3e0df2bcc77790bcfc08e642ac690a414..71b5e833dd9e716d902dc7bc56fb65ade73c7347 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 debf8925f06f4539722f269529c32714ec2c5394..7d6e4ca28d696ac539f1e690eee8d36c8635f917 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 ee58cde8ee3bdd22a22e8b8e87f7c9d887400bf4..73e80b917f129faabc11621706c02781cef0cf89 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 9d442ee050bdd0da3259db18d65255b44575895e..16bcb80878997cfe91a52231ec0b315451201244 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 ae9cf740633e19257a4ddfab003eff17c96e0947..be38198d98b24f31c277e58163b99b93f83d6eaa 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 3ab8d1a303cd63024cbb84e3b0198f6909521d7d..a74ce2e3c33eb402c58418870bc7b1cf62a29285 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 3d1ebaabd1b6601a7f5d59483434c573a0bde8c7..1b405a7ed14fcfe3df8c6198041facd6b06a7f99 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 a316d368b69798a779d76bfe23e6787228a0fc11..2208ebbd8c4c02243fc6a9717110ac90450f25b8 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 f1f38c8cdc7481250e9904945702a6f1932868a8..6cb3aa5cbc795438f25168d42e418f761dd6174b 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 ea90a90b41a036ee608f00cf79ca3f57e17abcdd..50a9990760f30ad14b3817a4d48ac72353ad9b62 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 facbd603adf616aaa67a9b99456bd4b8f8be7177..9ba47b0a47b9311cda6a80eedf256502bd748fb4 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 888bf43df07e8c2d302ae28aa7e9ff40ab6a62a3..19f2645e60761435bfdc3ca4ad0a4c96b63b87a5 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 350145da76691f0c4b111360a9fe2df30fbb1a24..12ce18fa6b741d4d21a0353bec1441a2419be6f0 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 a5af9e3351904aa2777fe0113ee716d435e76d82..fefd0331a2ded935d79d11af707433fcc401611e 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 c9f071b0a0ab70b647bec3633571059934ece1bc..120921366e842d212df005329e17a2fcf270c055 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 a7a36209a193384d2e4dd932fbf2308c83b78efa..13e5fbafdf2f71573a4d098e246e8545a7a0ea8c 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 6ce8b4a35a238f7e37ab17dce3920f72e72d5f3f..9c467b096f035e7ba68dbb4edfb24e8cd531c1c8 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 1ae7a54d4f12cc5cb649bf067a8670afc8cadb39..d7986ee180124f560d0aab2c8a5f4e45db2f9820 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 06c040902444f4a0a7c2143952d475ee240640e2..5c6c3fd557d7fcbf4cde4a757ac1c4c862019b05 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 2ec981e861110d4984bd4f11ee5230a934902ab1..2ed4dc1f07fdeac2f43f3e94d41a96b3f76464d9 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 357b878607ca86a84a0130a8026efca689a0579c..6e74ecea55a39223b77e641070487f59e26cbd6e 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 65705a3c7ce1ee605d91c32889304beee2f70741..bd6977eedcb860a16ff8f6424f00cc150bd0877b 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 1649c2c480466aebe3dd318089e6dd73b4de468c..e54639738c8e8f8e3087906f21b2527fb135c654 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 ae03b11129614ba43d9a83eb089f6639091c8c66..179168ec63e9f81c7ae154b95493bd3828e75f6f 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 74961f9026d160650f68a5880c1a8a4d8b43c147..f2e68807f277c5009641c54f5198bebb7cb1c28f 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 f13a87dfa0681b32cbe0e37cd4aaa686ca3cdda7..d8ba8ec60c6ce6c1030e0e11f25ac456a301385a 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 f2ae9b77c285733e50b4b496407471149650d290..49d54d44b8e78be6d110c41db97312ef66ff89aa 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 5fdab6c6371d15392ad253277aba73ec54fdf0eb..e97f12b1a78004d07eb711d110a2805dc1808cd2 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 eafc14282892ad9914fca71b14275ad8f183c02a..6fd9ec170dbe471e3e4a6e581e758c40d7a5ad11 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 2e49855d7cf8aff804b10ae778b055c886ace8a0..8795947c00dde0a7e959fd8dab0b77dab2c7ff1c 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 9677a1887e572029a74ebb3dfa49b3f95b1ccb07..768db66eada5ea06c0595df6db4610522f01ec6c 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 9fa4a94d83c3415102df278f7d63b43b7ab493cb..76bea22f734f94c663f369dba031e0fab27a0410 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 534c1cbbb2f355deb7d7b69a19b7e5ac1c309989..f64139e0b3dc5010b28f71815ed6d97ddaa1de4a 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 627da2e079c9ee886b99a64bb67c7da9a19f5c9c..7b5ffd13a8878a36cf271401528273bc6ff41890 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 eb2053845c9c4d0430a4b767f66d8a4f220efa7b..73b6d40450aca51d94245be59490f6ee3454241d 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 4109f890ae60fa79634891410a646d52e6f79310..7830e550c37af2ed36ed9fdfeb50d91954d82722 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 3275231d396b02ee9abf9fcc157f6d1ff44e8de4..0c039993953ad56ea7c0d04f485b8ef902665e21 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 11a5614591b10cc1ae0d72150050fbbeb842273b..ca5cb52928e3c6a302364dffa2cbe45029fc5e58 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 75f383c0b9d3219b95c8e28be1b95272c70fb1d9..f2761e24cf40a6e503836c668a828aab1f4bb427 100644 (file)
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.4.7-gf267e674"
+#define DTC_VERSION "DTC 1.5.0-g702c1b6c"
index 9fd3d8ed731a8507a87b5257f14bd90d2048c2eb..12475508751082064b823da637853a9d10797647 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 e93336baaaeda457e83e30ec214a047bef98db83..c586d32dd2c358580ee7573b722804c01fe3ff2d 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 00a6d7e5497126147dc0d9a564c4a6525fff6079..1ebcf52cd0f9e0402624b748d3818c27d40384ee 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 593f8879c6410d7189a4dfc0eab58bcb47f40452..47f6f3ea07717e435e3ea6210f3b23b23d2f4eb4 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 e17837f1d3f2bfd8cf712b6d2a0e3a42b88a94ae..ae6504d07fd6123b6a9d984bec070ece4c59d613 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 3f327e21f60e23c25b7bc14179afcea6f9104868..ab30fe724c43c2b1e6e76433ace8466addc4a392 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 ef3678c24babaf506b724e73d1f67a2d7f546661..40e16e871ae2514d672421ad6cf100b4ecea15fd 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 6006154d36bd22548e2b7223097d0f4a917ae5ae..501fdcc5e999eb2dada576d10ed70eada7380588 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 cbc7658ee27d5d279ea1d17230071c47505ba8eb..4fb16f3166268fd5686b303797561374f58470cf 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 86c267540ccc70e74fbb4962210e498aae65766d..f9ab98238aeff1974ebe917bc0eba7f0f32e1be9 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 694091f3ef9d29cd1c36326a11aba3c4a54685d9..49c26ea9dd984db18f0709cb9a9eb95e47113dba 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 cbafe3bf082ec78f82388a8f138a35f76da711ea..b7c1ef757178ad21b0b622a0139d716e72f6f332 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 592dfbfa9fb30d6804043a5bad23b9f683adefd8..0243086fb16854d9c7555b13f4ad3f3b2b96c456 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 ce7fc87a49a7e9147ddfed74f4691d62532ed5fa..82773cc35d356a82d20287e3982122d61dd92fbc 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 09fd6fa18e1a48775ad9149e78815fe4d55bd2fb..f56eec5ea4c7fc26658bc55a25c7eadb9203e231 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 b03dd56a4782b481fc4e176b022d652ec60df2e4..e8ca6dc97e963e207017773b6a939b26319e5521 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 009147d4718eeead8117413a8bdf95108c84e4dd..2d29df4a0a53c09acdfa7fbe5f7f66bf0bc5f291 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 86b87332b9e518102036b0072c8f81c436a41117..de75b9feaaedda1e74d381b567effa8eb784f665 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 d46be47633af4f0ca38ef3c52170e2b7234a6010..4e18ae5282a69d222523d3db7a774ab9a5857aca 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 c6cb2d9b29059ff004391f7d43e155b0c91b03df..a1ffe2eb4d5f5f5eb87f4f544f8b4014070f2989 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 79131efa963431736f3b11435a1cff7865ff3978..81519c804888c613fb86afc164f67238fcd333ba 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 0ac3e520653f562f582a91b09d4791aeab81b8b5..85beef265cc8255b6274374a53dbcdd0ac648263 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 7a3e138594c17520bcaae7be44bf7e2536d16760..c16b0ffe8cfc54ec83c0328d1cb9d98ab1cc4937 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 d329825aa31be379e56356b5659042a2c74ea20a..cfb297e6ef5ae43ed902e276b77bd9da0b0b4f99 100644 (file)
@@ -10,4 +10,4 @@ all: ihex2fw
 clean:
        $(RM) ihex2fw
 
-.PHONY: all clean
\ No newline at end of file
+.PHONY: all clean
index a22b6e8fad46eecb68f2a61455895f0279a5efab..7399eb7f13786f9d2e45d4fb9eef5e6123285ca4 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 2fe12b40d5035a7b459720476e7ab7002b04c9d4..c2152f3dd02d41a559f8d62221ea34313ca93277 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 9781ca79794af774ca86b3ef0708283cfa73db0a..25b43a8c2b15903a15a712e611f3e7e982f8921d 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 2bfddb6d6d3bcec435e7f6c5754252ac4287556e..8219a30853d283fa65baa1be4f16036d7cf542a8 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 a4320c4b44dc9ccf021e3fc3376640593d46aa4f..f901076aa2ea0cbc2e76bd71e5e05f9c7a48485b 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 1cbb12e284a689329feb78eeddfa8896cc21f3a5..f236cc2954502b1db162bbea8e49845120afea59 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 cffdd4eb0a57ccc76b6da44b6f557cec1798f72d..8e14d555c197849c7160b0852c70af54d8d9fca2 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 fc27f890155baf9308dd38e641ea35605870719d..ceb52b9526375de63cadef26256a110d5e5637b8 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 9ef2ab1a0c0874276893537334c00cb0f7a513ea..b7fa0c8551db4b2d84dad3fca42572d299e5cdd6 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 7318fb054ae9673924ce20295f01999c9407ecec..00235f5932f04b5b9a11d396168a4cf8418539e5 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 19e667911496cd42bb8a513fd122706e0f6c3d17..af2023d818a5a9dcaee4b08367d2b0557d440048 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 ee864fa07d8ec4057e721e409c48f15abac90aef..221e3fa4668024843e183549d1acecabfd2076d9 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 265b7822f591613f4c9ffe218ee0b288b33dbb33..f36262e0f655335677c445f37486c69f3b8c19b8 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 b701a01cfcb62c619860783fb387c177d352bcbd..dd9a66700f96e5335ffd78128409ac9e49350498 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 d2ad85fb01ac07d9d3a13c5cbdaa6909e6f7ec32..b430f962e32367270ab11ff23fa11dd178b8bee5 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 241919ef1eaca2c0d053b96a83dcf068480d5e22..f95c08343b487d4a4ec2698d18b08d191a612675 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 6a3eec8da351cc9dfed7c4d8fbdb6ad620fbc16f..429226bc6a928392f043f5aeda3a3ed8c11830aa 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 4daf520bada1d774568e32908c6b7d1f2a0c2311..8c063646f2a00dd293f8fb944615ca870fad7fcf 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 1a23617f34d9557328e4572ad3a960570a6f2461..3ab5ec3da9f42eaadf6efd12b4bb63f4b69e2487 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 07733719578358bf6c983eabe192dd38ae59cf58..1c8a1963d03f8acf349ae209e5db03ab79e2614e 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 0fbed67bf4f6c0cdbb144941fec512d551c3db55..aca3491174a1edd1ac6fe422615370a450b9156b 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 84f28f147fb6696a55a4f6bb7bd194368bb1bded..5943c816c07ce135ff8c6fcb830d98e815d7503a 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 73818f1b2ef8093e4addf1f8997aad82f7e8602b..68092d15e12b5ffaaa1f974cf625a073ffe6797a 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 8e48117a3f3dc763a0d18f69db0a23f9acafe632..be5eae1df7eb6e5e5fdcc129bffea77a06d2cbc2 100644 (file)
@@ -7,4 +7,3 @@ initramfs_data.cpio.gz
 initramfs_data.cpio.bz2
 initramfs_data.cpio.lzma
 initramfs_list
-include
index 4a70ae43c9cb5366abbe135415de85c351fb4270..6a89eb019275b6f209d45d66884a766672dc88eb 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 1be486d5d7cb495c81a6e8168421cc699c774a2d..e2bb5bd602270cace47548f9efe56c9f2331e48d 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 bd5c55916d0d12036aaa7ca3bacb572e11ed5f31..f645c0fbf7ecef90aa7007709b90acf05756e558 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 198e5171e1f77e21c8d347b2763cf38d9c0005dd..38b4c910b6c3861609979f6292f81462ee39d595 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 da740764a7ee6b27bc643360fd7c9be91e25acf9..3dd8238ed2462eeeb04e5c7cfa2735e3782d02bd 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 be3c9cdca9f3b9de790d1a225db9dc932216ccdb..87927f7e1ee7072f714958ded4ff2da1126b8fa5 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 2e6fc7c66a11311b02c8f7d034b636195e4acce3..58e4f88b2b9fb4ecd0765f6e653f8dc14b5e0423 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 2f2d24a4dd5c2e2ef18d9bbc5f2468a627af6ced..b4ab59dd6846003cd5bfbfa38ca708880af6cdf1 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;
        }